<commit_before>use std::rc::Rc;
use std::path::Path;
use std::cell::Cell;
use std::collections::BTreeMap;
use url::Url;
use regex::Regex;
use html5ever::tree_builder::TreeSink;
use html5ever::rcdom::Node;
use html5ever::rcdom::NodeData::{Element, Text};
use html5ever::rcdom::Handle;
use html5ever::rcdom::NodeData::{
    Document,
    Doctype,
    Comment,
    ProcessingInstruction
};
use html5ever::rcdom::RcDom;
use dom;

pub static PUNCTUATIONS: &'static str = r"([、。，．！？]|\.[^A-Za-z0-9]|,[^0-9]|!|\?)";
pub static POSITIVE: &'static str = "article|body|content|entry|hentry|main|page\
                                     |pagination|post|text|blog|story";
pub static NEGATIVE: &'static str = "combx|comment|com|contact|foot|footer|footnote\
                                     |masthead|media|meta|outbrain|promo|related\
                                     |scroll|shoutbox|sidebar|sponsor|shopping\
                                     |tags|tool|widget|form|textfield";
static TAGS: [&'static str; 10]  = [
    "a", "blockquote", "dl", "div", "img", "ol", "p", "pre", "table", "ul",
];

pub struct Candidate {
    pub node:  Rc<Node>,
    pub score: Cell<f32>,
}

pub fn fix_img_path(handle: Handle, url: &Url) -> bool {
    let src = dom::get_attr("src", handle.clone());
    if src.is_none() {
        return false
    }
    let s = src.unwrap();
    if !s.starts_with("//") && !s.starts_with("http://") && s.starts_with("https://") {
        match url.join(&s) {
            Ok(new_url) => dom::set_attr("src", new_url.as_str(), handle),
            Err(_)      => (),
        }
    }
    true
}

pub fn get_link_density(handle: Handle) -> f32 {
    let text_length = dom::text_len(handle.clone()) as f32;
    if text_length == 0.0 {
        return 0.0;
    }
    let mut link_length = 0.0;
    let mut links: Vec<Rc<Node>> = vec![];
    dom::find_node(handle.clone(), "a", &mut links);
    for link in links.iter() {
        link_length += dom::text_len(link.clone()) as f32;
    }
    link_length / text_length
}

pub fn is_candidate(handle: Handle) -> bool {
    let text_len = dom::text_len(handle.clone());
    if text_len < 20 {
        return false
    }
    let n: &str = &dom::get_tag_name(handle. clone()).unwrap_or("".to_string());
    match n {
        "p" => true,
        "div" | "article" | "center" | "section" =>
            !dom::has_nodes(handle.clone(), &TAGS.iter().map(|t| *t).collect()),
        _ => false
    }
}

pub fn init_content_score(handle: Handle) -> f32 {
    let tag_name = dom::get_tag_name(handle.clone()).unwrap_or("".to_string());
    match tag_name.as_ref() {
        "article"    => 10.0,
        "div"        => 5.0,
        "blockquote" => 3.0,
        "form"       => -3.0,
        "th"         => 5.0,
        _            => 0.0,
    }
}

pub fn calc_content_score(handle: Handle) -> f32 {
    let mut score: f32 = 1.0;
    score += get_class_weight(handle.clone());
    let mut text = String::new();
    dom::extract_text(handle.clone(), &mut text, true);
    let re = Regex::new(PUNCTUATIONS).unwrap();
    let mat = re.find_iter(&text);
    score += mat.count() as f32;
    score += f32::min(f32::floor(text.chars().count() as f32 / 100.0), 3.0);
    return score
}

pub fn get_class_weight(handle: Handle) -> f32 {
    let mut weight: f32 = 0.0;
    match handle.data {
        Element { name: _, ref attrs, .. } => {
            for prop in ["id", "class"].iter() {
                if let Some(class) = dom::attr(prop, &attrs.borrow()) {
                    if Regex::new(POSITIVE).unwrap().is_match(&class) {
                        weight += 25.0
                    };
                    if Regex::new(NEGATIVE).unwrap().is_match(&class) {
                        weight -= 25.0
                    }
                }
            }
        },
        _ => (),
    };
    weight
}

pub fn clean(mut dom: &mut RcDom, id: &Path, handle: Handle, url: &Url, candidates: &BTreeMap<String, Candidate>) -> bool {
    let mut useless = false;
    match handle.data {
        Document       => (),
        Doctype { .. } => (),
        Text { ref contents } => {
            let s = contents.borrow();
            if s.trim().len() == 0 {
                useless = true
            }
        },
        Comment { .. } => useless = true,
        Element { ref name, ref attrs, .. } => {
            let tag_name = name.local.as_ref();
            match tag_name.to_lowercase().as_ref() {
                "script" | "link" | "style" | "noscript" | "meta"
                    | "h1" | "object" | "header" | "footer" | "aside" => {
                    useless = true
                },
                "form" | "table" | "ul" | "div" => {
                    useless = is_useless(id, handle.clone(), candidates)
                },
                "img" => useless = fix_img_path(handle.clone(), url),
                _     => (),
            }
            dom::clean_attr("id"   , &mut *attrs.borrow_mut());
            dom::clean_attr("class", &mut *attrs.borrow_mut());
            dom::clean_attr("style", &mut *attrs.borrow_mut());
        },
        ProcessingInstruction { .. } => unreachable!()
    }
    let mut useless_nodes = vec![];
    for (i, child) in handle.children.borrow().iter().enumerate() {
        let pid = id.join(i.to_string());
        if clean(&mut dom, pid.as_path(), child.clone(), url, candidates) {
            useless_nodes.push(child.clone());
        }
    }
    for node in useless_nodes.iter() {
        dom.remove_from_parent(node);
    }
    if dom::is_empty(handle) {
        useless = true
    }
    useless
}

pub fn is_useless(id: &Path, handle: Handle, candidates: &BTreeMap<String, Candidate>) -> bool {
    let tag_name = &dom::get_tag_name(handle.clone()).unwrap_or("".to_string());
    let weight = get_class_weight(handle.clone());
    let score = id.to_str()
        .and_then(|id| candidates.get(id))
        .map(|c| c.score.get()).unwrap_or(0.0);
    if weight + score < 0.0 {
        return true
    }
    let mut p_nodes:     Vec<Rc<Node>> = vec![];
    let mut img_nodes:   Vec<Rc<Node>> = vec![];
    let mut li_nodes:    Vec<Rc<Node>> = vec![];
    let mut input_nodes: Vec<Rc<Node>> = vec![];
    let mut embed_nodes: Vec<Rc<Node>> = vec![];
    dom::find_node(handle.clone(), "p"     , &mut p_nodes);
    dom::find_node(handle.clone(), "img"   , &mut img_nodes);
    dom::find_node(handle.clone(), "li"    , &mut li_nodes);
    dom::find_node(handle.clone(), "input" , &mut input_nodes);
    dom::find_node(handle.clone(), "embed" , &mut embed_nodes);
    let p_count        = p_nodes.len();
    let img_count      = img_nodes.len();
    let li_count       = li_nodes.len() as i32 - 100;
    let input_count    = input_nodes.len();
    let embed_count    = embed_nodes.len();
    let link_density   = get_link_density(handle.clone());
    let content_length = dom::text_len(handle.clone());

    if img_count > p_count {
        return true
    }
    if li_count > p_count as i32 && tag_name != "ul" && tag_name != "ol" {
        return true
    }
    if input_count as f32 > f32::floor(p_count as f32 / 3.0) {
        return true
    }
    if content_length < 25 && (img_count == 0 || img_count > 2) {
        return true
    }
    if weight < 25.0 && link_density > 0.2 {
        return true
    }
    if (embed_count == 1 && content_length < 35) || embed_count > 1 {
        return true
    }
    return false
}

pub fn is_link_list(handle: Handle) -> bool {
    let rate = evaluate_list(handle);
    rate > 7.5
}

fn evaluate_list(handle: Handle) -> f32 {
    let mut hit: i32 = 0;
    let mut len: i32 = 0;
    for child in handle.children.borrow().iter() {
        let c = child.clone();
        match c.data {
            Element { ref name, .. } => {
                let tag_name = name.local.as_ref();
                match tag_name.to_lowercase().as_ref() {
                    "li" | "dt" | "dd" => {
                        len += 1;
                        if dom::has_link(child.clone()) {
                            hit += 1
                        }
                    }
                    _ => (),
                }
            },
            _ => ()
        }
    }
    if len == 0 {
        0.0
    } else {
        9.0 * ((hit / len) as f32).powi(2) + 1.0
    }
}
<commit_msg>Refactoring: TAGS -> BLOCK_CHILD_TAGS<commit_after>use std::rc::Rc;
use std::path::Path;
use std::cell::Cell;
use std::collections::BTreeMap;
use url::Url;
use regex::Regex;
use html5ever::tree_builder::TreeSink;
use html5ever::rcdom::Node;
use html5ever::rcdom::NodeData::{Element, Text};
use html5ever::rcdom::Handle;
use html5ever::rcdom::NodeData::{
    Document,
    Doctype,
    Comment,
    ProcessingInstruction
};
use html5ever::rcdom::RcDom;
use dom;

pub static PUNCTUATIONS: &'static str = r"([、。，．！？]|\.[^A-Za-z0-9]|,[^0-9]|!|\?)";
pub static POSITIVE: &'static str = "article|body|content|entry|hentry|main|page\
                                     |pagination|post|text|blog|story";
pub static NEGATIVE: &'static str = "combx|comment|com|contact|foot|footer|footnote\
                                     |masthead|media|meta|outbrain|promo|related\
                                     |scroll|shoutbox|sidebar|sponsor|shopping\
                                     |tags|tool|widget|form|textfield";
static BLOCK_CHILD_TAGS: [&'static str; 10] = [
    "a", "blockquote", "dl", "div", "img", "ol", "p", "pre", "table", "ul",
];

pub struct Candidate {
    pub node:  Rc<Node>,
    pub score: Cell<f32>,
}

pub fn fix_img_path(handle: Handle, url: &Url) -> bool {
    let src = dom::get_attr("src", handle.clone());
    if src.is_none() {
        return false
    }
    let s = src.unwrap();
    if !s.starts_with("//") && !s.starts_with("http://") && s.starts_with("https://") {
        match url.join(&s) {
            Ok(new_url) => dom::set_attr("src", new_url.as_str(), handle),
            Err(_)      => (),
        }
    }
    true
}

pub fn get_link_density(handle: Handle) -> f32 {
    let text_length = dom::text_len(handle.clone()) as f32;
    if text_length == 0.0 {
        return 0.0;
    }
    let mut link_length = 0.0;
    let mut links: Vec<Rc<Node>> = vec![];
    dom::find_node(handle.clone(), "a", &mut links);
    for link in links.iter() {
        link_length += dom::text_len(link.clone()) as f32;
    }
    link_length / text_length
}

pub fn is_candidate(handle: Handle) -> bool {
    let text_len = dom::text_len(handle.clone());
    if text_len < 20 {
        return false
    }
    let n: &str = &dom::get_tag_name(handle. clone()).unwrap_or("".to_string());
    match n {
        "p" => true,
        "div" | "article" | "center" | "section" =>
            !dom::has_nodes(handle.clone(), &BLOCK_CHILD_TAGS.iter().map(|t| *t).collect()),
        _ => false
    }
}

pub fn init_content_score(handle: Handle) -> f32 {
    let tag_name = dom::get_tag_name(handle.clone()).unwrap_or("".to_string());
    match tag_name.as_ref() {
        "article"    => 10.0,
        "div"        => 5.0,
        "blockquote" => 3.0,
        "form"       => -3.0,
        "th"         => 5.0,
        _            => 0.0,
    }
}

pub fn calc_content_score(handle: Handle) -> f32 {
    let mut score: f32 = 1.0;
    score += get_class_weight(handle.clone());
    let mut text = String::new();
    dom::extract_text(handle.clone(), &mut text, true);
    let re = Regex::new(PUNCTUATIONS).unwrap();
    let mat = re.find_iter(&text);
    score += mat.count() as f32;
    score += f32::min(f32::floor(text.chars().count() as f32 / 100.0), 3.0);
    return score
}

pub fn get_class_weight(handle: Handle) -> f32 {
    let mut weight: f32 = 0.0;
    match handle.data {
        Element { name: _, ref attrs, .. } => {
            for prop in ["id", "class"].iter() {
                if let Some(class) = dom::attr(prop, &attrs.borrow()) {
                    if Regex::new(POSITIVE).unwrap().is_match(&class) {
                        weight += 25.0
                    };
                    if Regex::new(NEGATIVE).unwrap().is_match(&class) {
                        weight -= 25.0
                    }
                }
            }
        },
        _ => (),
    };
    weight
}

pub fn clean(mut dom: &mut RcDom, id: &Path, handle: Handle, url: &Url, candidates: &BTreeMap<String, Candidate>) -> bool {
    let mut useless = false;
    match handle.data {
        Document       => (),
        Doctype { .. } => (),
        Text { ref contents } => {
            let s = contents.borrow();
            if s.trim().len() == 0 {
                useless = true
            }
        },
        Comment { .. } => useless = true,
        Element { ref name, ref attrs, .. } => {
            let tag_name = name.local.as_ref();
            match tag_name.to_lowercase().as_ref() {
                "script" | "link" | "style" | "noscript" | "meta"
                    | "h1" | "object" | "header" | "footer" | "aside" => {
                    useless = true
                },
                "form" | "table" | "ul" | "div" => {
                    useless = is_useless(id, handle.clone(), candidates)
                },
                "img" => useless = fix_img_path(handle.clone(), url),
                _     => (),
            }
            dom::clean_attr("id"   , &mut *attrs.borrow_mut());
            dom::clean_attr("class", &mut *attrs.borrow_mut());
            dom::clean_attr("style", &mut *attrs.borrow_mut());
        },
        ProcessingInstruction { .. } => unreachable!()
    }
    let mut useless_nodes = vec![];
    for (i, child) in handle.children.borrow().iter().enumerate() {
        let pid = id.join(i.to_string());
        if clean(&mut dom, pid.as_path(), child.clone(), url, candidates) {
            useless_nodes.push(child.clone());
        }
    }
    for node in useless_nodes.iter() {
        dom.remove_from_parent(node);
    }
    if dom::is_empty(handle) {
        useless = true
    }
    useless
}

pub fn is_useless(id: &Path, handle: Handle, candidates: &BTreeMap<String, Candidate>) -> bool {
    let tag_name = &dom::get_tag_name(handle.clone()).unwrap_or("".to_string());
    let weight = get_class_weight(handle.clone());
    let score = id.to_str()
        .and_then(|id| candidates.get(id))
        .map(|c| c.score.get()).unwrap_or(0.0);
    if weight + score < 0.0 {
        return true
    }
    let mut p_nodes:     Vec<Rc<Node>> = vec![];
    let mut img_nodes:   Vec<Rc<Node>> = vec![];
    let mut li_nodes:    Vec<Rc<Node>> = vec![];
    let mut input_nodes: Vec<Rc<Node>> = vec![];
    let mut embed_nodes: Vec<Rc<Node>> = vec![];
    dom::find_node(handle.clone(), "p"     , &mut p_nodes);
    dom::find_node(handle.clone(), "img"   , &mut img_nodes);
    dom::find_node(handle.clone(), "li"    , &mut li_nodes);
    dom::find_node(handle.clone(), "input" , &mut input_nodes);
    dom::find_node(handle.clone(), "embed" , &mut embed_nodes);
    let p_count        = p_nodes.len();
    let img_count      = img_nodes.len();
    let li_count       = li_nodes.len() as i32 - 100;
    let input_count    = input_nodes.len();
    let embed_count    = embed_nodes.len();
    let link_density   = get_link_density(handle.clone());
    let content_length = dom::text_len(handle.clone());

    if img_count > p_count {
        return true
    }
    if li_count > p_count as i32 && tag_name != "ul" && tag_name != "ol" {
        return true
    }
    if input_count as f32 > f32::floor(p_count as f32 / 3.0) {
        return true
    }
    if content_length < 25 && (img_count == 0 || img_count > 2) {
        return true
    }
    if weight < 25.0 && link_density > 0.2 {
        return true
    }
    if (embed_count == 1 && content_length < 35) || embed_count > 1 {
        return true
    }
    return false
}

pub fn is_link_list(handle: Handle) -> bool {
    let rate = evaluate_list(handle);
    rate > 7.5
}

fn evaluate_list(handle: Handle) -> f32 {
    let mut hit: i32 = 0;
    let mut len: i32 = 0;
    for child in handle.children.borrow().iter() {
        let c = child.clone();
        match c.data {
            Element { ref name, .. } => {
                let tag_name = name.local.as_ref();
                match tag_name.to_lowercase().as_ref() {
                    "li" | "dt" | "dd" => {
                        len += 1;
                        if dom::has_link(child.clone()) {
                            hit += 1
                        }
                    }
                    _ => (),
                }
            },
            _ => ()
        }
    }
    if len == 0 {
        0.0
    } else {
        9.0 * ((hit / len) as f32).powi(2) + 1.0
    }
}
<|endoftext|>


<commit_before>
#![feature(braced_empty_structs)]
extern crate capnp;

#[macro_use]
extern crate rustfbp;

use rustfbp::component::*;

component! {
  Nand,
  inputs(input: boolean),
  inputs_array(),
  outputs(output: boolean),
  outputs_array(),
  option(),
  acc(),
  fn run(&mut self) {
    let mut ip = self.ports.recv("input".into()).expect("cannot receive");
    let m = ip.get_reader().expect("cannot get reader");
    let m: boolean::Reader = m.get_root().expect("not a boolean reader");
    let n = m.get_boolean();
    let mut new_m = super::capnp::message::Builder::new_default();
    {
      let mut boolean = new_m.init_root::<boolean::Builder>();
      boolean.set_boolean(!n);
    }
    ip.write_builder(&new_m);
    self.ports.send("output".into(), ip).expect("cannot send date");
  }

  mod boolean_capnp {
    include!("maths_boolean_capnp.rs");
  }
  use self::boolean_capnp::boolean;
}
<commit_msg>Problem: Nand logic gate only had 1 input Solution: add a b input + logic<commit_after>
#![feature(braced_empty_structs)]
extern crate capnp;

#[macro_use]
extern crate rustfbp;

use rustfbp::component::*;

component! {
  Nand,
  inputs(a: boolean, b: boolean),
  inputs_array(),
  outputs(output: boolean),
  outputs_array(),
  option(),
  acc(),
  fn run(&mut self) {
    let mut ip_a = self.ports.recv("a".into()).expect("cannot receive");
    let mut ip_b = self.ports.recv("b".into()).expect("cannot receive");
    let a_reader = ip_a.get_reader().expect("cannot get reader");
    let b_reader = ip_b.get_reader().expect("cannot get reader");
    let a_reader: boolean::Reader = a_reader.get_root().expect("not a boolean reader");
    let b_reader: boolean::Reader = b_reader.get_root().expect("not a boolean reader");
    let a = a_reader.get_boolean();
    let b = b_reader.get_boolean();
    let mut new_out = super::capnp::message::Builder::new_default();
    {
      let mut boolean = new_out.init_root::<boolean::Builder>();
      boolean.set_boolean(if a == true && b == true {false} else {true});
    }
    ip_a.write_builder(&new_out);
    self.ports.send("output".into(), ip_a).expect("cannot send date");
  }

  mod boolean_capnp {
    include!("maths_boolean_capnp.rs");
  }
  use self::boolean_capnp::boolean;
}
<|endoftext|>


<commit_before>//! This pass is overloaded and runs two different lints.
//!
//! - MISSING_DOC_CODE_EXAMPLES: this looks for public items missing doc-tests
//! - PRIVATE_DOC_TESTS: this looks for private items with doc-tests.

use super::{span_of_attrs, Pass};
use crate::clean;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
use rustc_session::lint;

pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
    name: "check-private-items-doc-tests",
    run: check_private_items_doc_tests,
    description: "check private items doc tests",
};

struct PrivateItemDocTestLinter<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
}

impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
    fn new(cx: &'a DocContext<'tcx>) -> Self {
        PrivateItemDocTestLinter { cx }
    }
}

pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
    let mut coll = PrivateItemDocTestLinter::new(cx);

    coll.fold_crate(krate)
}

impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
    fn fold_item(&mut self, item: Item) -> Option<Item> {
        let cx = self.cx;
        let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);

        look_for_tests(&cx, &dox, &item);

        self.fold_item_recur(item)
    }
}

pub(crate) struct Tests {
    pub(crate) found_tests: usize,
}

impl Tests {
    pub(crate) fn new() -> Tests {
        Tests { found_tests: 0 }
    }
}

impl crate::test::Tester for Tests {
    fn add_test(&mut self, _: String, _: LangString, _: usize) {
        self.found_tests += 1;
    }
}

pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
    !matches!(item_kind,
        clean::StructFieldItem(_)
        | clean::VariantItem(_)
        | clean::AssocConstItem(_, _)
        | clean::AssocTypeItem(_, _)
        | clean::TypedefItem(_, _)
        | clean::StaticItem(_)
        | clean::ConstantItem(_)
        | clean::ExternCrateItem(_, _)
        | clean::ImportItem(_)
        | clean::PrimitiveItem(_)
        | clean::KeywordItem(_)
    )
}

pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
    let hir_id = match cx.as_local_hir_id(item.def_id) {
        Some(hir_id) => hir_id,
        None => {
            // If non-local, no need to check anything.
            return;
        }
    };

    let mut tests = Tests::new();

    find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);

    if tests.found_tests == 0 {
        if should_have_doc_example(&item.inner) {
            debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
            let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
            cx.tcx.struct_span_lint_hir(
                lint::builtin::MISSING_DOC_CODE_EXAMPLES,
                hir_id,
                sp,
                |lint| lint.build("missing code example in this documentation").emit(),
            );
        }
    } else if rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
        && tests.found_tests > 0
        && !cx.renderinfo.borrow().access_levels.is_public(item.def_id)
    {
        cx.tcx.struct_span_lint_hir(
            lint::builtin::PRIVATE_DOC_TESTS,
            hir_id,
            span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
            |lint| lint.build("documentation test in private item").emit(),
        );
    }
}
<commit_msg>Rollup merge of #75953 - jyn514:missing-lints, r=Manishearth<commit_after>//! This pass is overloaded and runs two different lints.
//!
//! - MISSING_DOC_CODE_EXAMPLES: this lint is **UNSTABLE** and looks for public items missing doc-tests
//! - PRIVATE_DOC_TESTS: this lint is **STABLE** and looks for private items with doc-tests.

use super::{span_of_attrs, Pass};
use crate::clean;
use crate::clean::*;
use crate::core::DocContext;
use crate::fold::DocFolder;
use crate::html::markdown::{find_testable_code, ErrorCodes, LangString};
use rustc_session::lint;

pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass {
    name: "check-private-items-doc-tests",
    run: check_private_items_doc_tests,
    description: "check private items doc tests",
};

struct PrivateItemDocTestLinter<'a, 'tcx> {
    cx: &'a DocContext<'tcx>,
}

impl<'a, 'tcx> PrivateItemDocTestLinter<'a, 'tcx> {
    fn new(cx: &'a DocContext<'tcx>) -> Self {
        PrivateItemDocTestLinter { cx }
    }
}

pub fn check_private_items_doc_tests(krate: Crate, cx: &DocContext<'_>) -> Crate {
    let mut coll = PrivateItemDocTestLinter::new(cx);

    coll.fold_crate(krate)
}

impl<'a, 'tcx> DocFolder for PrivateItemDocTestLinter<'a, 'tcx> {
    fn fold_item(&mut self, item: Item) -> Option<Item> {
        let cx = self.cx;
        let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new);

        look_for_tests(&cx, &dox, &item);

        self.fold_item_recur(item)
    }
}

pub(crate) struct Tests {
    pub(crate) found_tests: usize,
}

impl Tests {
    pub(crate) fn new() -> Tests {
        Tests { found_tests: 0 }
    }
}

impl crate::test::Tester for Tests {
    fn add_test(&mut self, _: String, _: LangString, _: usize) {
        self.found_tests += 1;
    }
}

pub fn should_have_doc_example(item_kind: &clean::ItemEnum) -> bool {
    !matches!(item_kind,
        clean::StructFieldItem(_)
        | clean::VariantItem(_)
        | clean::AssocConstItem(_, _)
        | clean::AssocTypeItem(_, _)
        | clean::TypedefItem(_, _)
        | clean::StaticItem(_)
        | clean::ConstantItem(_)
        | clean::ExternCrateItem(_, _)
        | clean::ImportItem(_)
        | clean::PrimitiveItem(_)
        | clean::KeywordItem(_)
    )
}

pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) {
    let hir_id = match cx.as_local_hir_id(item.def_id) {
        Some(hir_id) => hir_id,
        None => {
            // If non-local, no need to check anything.
            return;
        }
    };

    let mut tests = Tests::new();

    find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None);

    if tests.found_tests == 0
        && rustc_feature::UnstableFeatures::from_environment().is_nightly_build()
    {
        if should_have_doc_example(&item.inner) {
            debug!("reporting error for {:?} (hir_id={:?})", item, hir_id);
            let sp = span_of_attrs(&item.attrs).unwrap_or(item.source.span());
            cx.tcx.struct_span_lint_hir(
                lint::builtin::MISSING_DOC_CODE_EXAMPLES,
                hir_id,
                sp,
                |lint| lint.build("missing code example in this documentation").emit(),
            );
        }
    } else if tests.found_tests > 0 && !cx.renderinfo.borrow().access_levels.is_public(item.def_id)
    {
        cx.tcx.struct_span_lint_hir(
            lint::builtin::PRIVATE_DOC_TESTS,
            hir_id,
            span_of_attrs(&item.attrs).unwrap_or(item.source.span()),
            |lint| lint.build("documentation test in private item").emit(),
        );
    }
}
<|endoftext|>


<commit_before>use std::collections::HashSet;

struct WorldMap{
    map: HashSet<(i8, i8)>
}

fn get_neighbours_coordinates(cell_coordinates: (i8,i8)) -> HashSet<(i8,i8)> {
    let mut neighbour_coordinates = HashSet::new();
    let (x, y) = cell_coordinates;
    neighbour_coordinates.insert((x-1, y-1));
    neighbour_coordinates.insert((x-1, y));
    neighbour_coordinates.insert((x-1, y+1));
    neighbour_coordinates.insert((x, y-1));
    neighbour_coordinates.insert((x, y+1));
    neighbour_coordinates.insert((x+1, y-1));
    neighbour_coordinates.insert((x+1, y));
    neighbour_coordinates.insert((x+1, y+1));
    return neighbour_coordinates;
}

impl WorldMap{

    fn empty() -> WorldMap {
        return WorldMap::new( HashSet::new() );
    }

    fn new(new_map: HashSet<(i8,i8)>) -> WorldMap {
        return WorldMap { map: new_map };
    }

    fn mark_cell_alive(&self, cell_coordinates: (i8, i8)) -> WorldMap {
        let mut new_map = self.map.clone();
        new_map.insert(cell_coordinates);
        let new_world = WorldMap::new(new_map);
        return new_world;
    }

    fn is_cell_alive(&self, cell_coordinates: (i8,i8)) -> bool {
        return self.map.contains(&cell_coordinates);
    }

    fn count_alive_neighbours(&self, cell_coordinates: (i8, i8)) -> usize {
        let neighbour_coordinates = get_neighbours_coordinates(cell_coordinates);
        let neighbours_alive = self.map.intersection(&neighbour_coordinates).collect::<Vec<&(i8,i8)>>();
        return neighbours_alive.len();
    }

    fn should_live(&self, cell_coordinates: (i8,i8)) -> bool {
        let alive_neighbours_count = self.count_alive_neighbours(cell_coordinates);
        let result = match alive_neighbours_count {
            0...1 => false,
            2...3 => true,
            _ => panic!("wrong number of neighbours: {}", alive_neighbours_count)
        };
        return result;
    }
}

#[test]
// rule 1
fn alive_cell_with_no_alive_neighbours_should_die() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let should_die = !new_world.should_live(coords);
    assert!(should_die);
}

#[test]
// rule 1
fn alive_cell_with_one_alive_neighbour_should_die() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1));
    let should_die = !new_world.should_live(coords);
    assert!(should_die);
}

#[test]
// rule 2
fn alive_cell_with_two_alive_neighbours_should_stay_alive() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1)).
        mark_cell_alive((x-1, y+1));
    let should_live = new_world.should_live(coords);
    assert!(should_live);
}

#[test]
// rule 2
fn alive_cell_with_three_alive_neighbours_should_stay_alive() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1)).
        mark_cell_alive((x-1, y)).
        mark_cell_alive((x-1, y+1));
    let should_live = new_world.should_live(coords);
    assert!(should_live);
}
#[test]
fn the_only_alive_cell_should_have_no_alive_neighbours() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let alive_neighbours_count = new_world.count_alive_neighbours(coords);
    assert_eq!(0, alive_neighbours_count);
}

#[test]
fn alive_neighbour_on_the_diagonal_should_count() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1));
    let alive_neighbours_count = new_world.count_alive_neighbours(coords);
    assert_eq!(1, alive_neighbours_count);
}

#[test]
fn is_cell_alive_should_return_true_for_alive_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let is_alive = new_world.is_cell_alive(coords);
    assert_eq!(true, is_alive);
}

#[test]
fn is_cell_alive_should_return_false_for_dead_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let is_alive = world.is_cell_alive(coords);
    assert_eq!(false, is_alive);
}
<commit_msg>support for rule 3 added<commit_after>use std::collections::HashSet;

struct WorldMap{
    map: HashSet<(i8, i8)>
}

fn get_neighbours_coordinates(cell_coordinates: (i8,i8)) -> HashSet<(i8,i8)> {
    let mut neighbour_coordinates = HashSet::new();
    let (x, y) = cell_coordinates;
    neighbour_coordinates.insert((x-1, y-1));
    neighbour_coordinates.insert((x-1, y));
    neighbour_coordinates.insert((x-1, y+1));
    neighbour_coordinates.insert((x, y-1));
    neighbour_coordinates.insert((x, y+1));
    neighbour_coordinates.insert((x+1, y-1));
    neighbour_coordinates.insert((x+1, y));
    neighbour_coordinates.insert((x+1, y+1));
    return neighbour_coordinates;
}

impl WorldMap{

    fn empty() -> WorldMap {
        return WorldMap::new( HashSet::new() );
    }

    fn new(new_map: HashSet<(i8,i8)>) -> WorldMap {
        return WorldMap { map: new_map };
    }

    fn mark_cell_alive(&self, cell_coordinates: (i8, i8)) -> WorldMap {
        let mut new_map = self.map.clone();
        new_map.insert(cell_coordinates);
        let new_world = WorldMap::new(new_map);
        return new_world;
    }

    fn is_cell_alive(&self, cell_coordinates: (i8,i8)) -> bool {
        return self.map.contains(&cell_coordinates);
    }

    fn count_alive_neighbours(&self, cell_coordinates: (i8, i8)) -> usize {
        let neighbour_coordinates = get_neighbours_coordinates(cell_coordinates);
        let neighbours_alive = self.map.intersection(&neighbour_coordinates).collect::<Vec<&(i8,i8)>>();
        return neighbours_alive.len();
    }

    fn should_live(&self, cell_coordinates: (i8,i8)) -> bool {
        let alive_neighbours_count = self.count_alive_neighbours(cell_coordinates);
        let result = match alive_neighbours_count {
            0...1 => false,
            2...3 => true,
            4...8 => false,
            _ => panic!("wrong number of neighbours: {}", alive_neighbours_count)
        };
        return result;
    }
}

#[test]
// rule 1
fn alive_cell_with_no_alive_neighbours_should_die() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let should_die = !new_world.should_live(coords);
    assert!(should_die);
}

#[test]
// rule 1
fn alive_cell_with_one_alive_neighbour_should_die() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1));
    let should_die = !new_world.should_live(coords);
    assert!(should_die);
}

#[test]
// rule 2
fn alive_cell_with_two_alive_neighbours_should_stay_alive() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1)).
        mark_cell_alive((x-1, y+1));
    let should_live = new_world.should_live(coords);
    assert!(should_live);
}

#[test]
// rule 2
fn alive_cell_with_three_alive_neighbours_should_stay_alive() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1)).
        mark_cell_alive((x-1, y)).
        mark_cell_alive((x-1, y+1));
    let should_live = new_world.should_live(coords);
    assert!(should_live);
}

#[test]
// rule 3
fn alive_cell_with_four_alive_neighbours_should_die() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1)).
        mark_cell_alive((x-1, y)).
        mark_cell_alive((x-1, y+1)).
        mark_cell_alive((x+1, y+1));
    let should_die = !new_world.should_live(coords);
    assert!(should_die);
}

#[test]
fn the_only_alive_cell_should_have_no_alive_neighbours() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let alive_neighbours_count = new_world.count_alive_neighbours(coords);
    assert_eq!(0, alive_neighbours_count);
}

#[test]
fn alive_neighbour_on_the_diagonal_should_count() {
    let (x, y) = (0,0);
    let coords = (x,y);
    let world = WorldMap::empty();
    let new_world = world.
        mark_cell_alive(coords).
        mark_cell_alive((x, y+1));
    let alive_neighbours_count = new_world.count_alive_neighbours(coords);
    assert_eq!(1, alive_neighbours_count);
}

#[test]
fn is_cell_alive_should_return_true_for_alive_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let new_world = world.mark_cell_alive(coords);
    let is_alive = new_world.is_cell_alive(coords);
    assert_eq!(true, is_alive);
}

#[test]
fn is_cell_alive_should_return_false_for_dead_cell() {
    let coords = (0,0);
    let world = WorldMap::empty();
    let is_alive = world.is_cell_alive(coords);
    assert_eq!(false, is_alive);
}
<|endoftext|>


<commit_before>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Various utility functions useful for writing I/O tests */

#[macro_escape];

use os;
use prelude::*;
use rand;
use rand::Rng;
use std::io::net::ip::*;
use sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, Relaxed};

macro_rules! iotest (
    { fn $name:ident() $b:block $($a:attr)* } => (
        mod $name {
            #[allow(unused_imports)];

            use super::super::*;
            use super::*;
            use io;
            use prelude::*;
            use io::*;
            use io::fs::*;
            use io::test::*;
            use io::net::tcp::*;
            use io::net::ip::*;
            use io::net::udp::*;
            #[cfg(unix)]
            use io::net::unix::*;
            use io::timer::*;
            use io::process::*;
            use unstable::running_on_valgrind;
            use str;
            use util;

            fn f() $b

            $($a)* #[test] fn green() { f() }
            $($a)* #[test] fn native() {
                use native;
                let (p, c) = Chan::new();
                native::task::spawn(proc() { c.send(f()) });
                p.recv();
            }
        }
    )
)

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    static mut next_offset: AtomicUint = INIT_ATOMIC_UINT;
    unsafe {
        base_port() + next_offset.fetch_add(1, Relaxed) as u16
    }
}

/// Get a temporary path which could be the location of a unix socket
pub fn next_test_unix() -> Path {
    if cfg!(unix) {
        os::tmpdir().join(rand::task_rng().gen_ascii_str(20))
    } else {
        Path::new(r"\\.\pipe\" + rand::task_rng().gen_ascii_str(20))
    }
}

/// Get a unique IPv4 localhost:port pair starting at 9600
pub fn next_test_ip4() -> SocketAddr {
    SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() }
}

/// Get a unique IPv6 localhost:port pair starting at 9600
pub fn next_test_ip6() -> SocketAddr {
    SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() }
}

/*
XXX: Welcome to MegaHack City.

The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> u16 {

    let base = 9600u16;
    let range = 1000u16;

    let bases = [
        ("32-opt", base + range * 1),
        ("32-nopt", base + range * 2),
        ("64-opt", base + range * 3),
        ("64-nopt", base + range * 4),
        ("64-opt-vg", base + range * 5),
        ("all-opt", base + range * 6),
        ("snap3", base + range * 7),
        ("dist", base + range * 8)
    ];

    // FIXME (#9639): This needs to handle non-utf8 paths
    let path = os::getcwd();
    let path_s = path.as_str().unwrap();

    let mut final_base = base;

    for &(dir, base) in bases.iter() {
        if path_s.contains(dir) {
            final_base = base;
            break;
        }
    }

    return final_base;
}

/// Raises the file descriptor limit when running tests if necessary
pub fn raise_fd_limit() {
    unsafe { darwin_fd_limit::raise_fd_limit() }
}

#[cfg(target_os="macos")]
#[allow(non_camel_case_types)]
mod darwin_fd_limit {
    /*!
     * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the
     * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low
     * for our multithreaded scheduler testing, depending on the number of cores available.
     *
     * This fixes issue #7772.
     */

    use libc;
    type rlim_t = libc::uint64_t;
    struct rlimit {
        rlim_cur: rlim_t,
        rlim_max: rlim_t
    }
    #[nolink]
    extern {
        // name probably doesn't need to be mut, but the C function doesn't specify const
        fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
                  oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
                  newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
        fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
        fn setrlimit(resource: libc::c_int, rlp: *rlimit) -> libc::c_int;
    }
    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;
    static RLIMIT_NOFILE: libc::c_int = 8;

    pub unsafe fn raise_fd_limit() {
        // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
        // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
        use ptr::mut_null;
        use mem::size_of_val;
        use os::last_os_error;

        // Fetch the kern.maxfilesperproc value
        let mut mib: [libc::c_int, ..2] = [CTL_KERN, KERN_MAXFILESPERPROC];
        let mut maxfiles: libc::c_int = 0;
        let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
        if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
                  mut_null(), 0) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling sysctl: {}", err);
            return;
        }

        // Fetch the current resource limits
        let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
        if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling getrlimit: {}", err);
            return;
        }

        // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
        rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);

        // Set our newly-increased resource limit
        if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling setrlimit: {}", err);
            return;
        }
    }
}

#[cfg(not(target_os="macos"))]
mod darwin_fd_limit {
    pub unsafe fn raise_fd_limit() {}
}
<commit_msg>Remove the dependence of std::io::test on rand.<commit_after>// Copyright 2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

/*! Various utility functions useful for writing I/O tests */

#[macro_escape];

use libc;
use os;
use prelude::*;
use std::io::net::ip::*;
use sync::atomics::{AtomicUint, INIT_ATOMIC_UINT, Relaxed};

macro_rules! iotest (
    { fn $name:ident() $b:block $($a:attr)* } => (
        mod $name {
            #[allow(unused_imports)];

            use super::super::*;
            use super::*;
            use io;
            use prelude::*;
            use io::*;
            use io::fs::*;
            use io::test::*;
            use io::net::tcp::*;
            use io::net::ip::*;
            use io::net::udp::*;
            #[cfg(unix)]
            use io::net::unix::*;
            use io::timer::*;
            use io::process::*;
            use unstable::running_on_valgrind;
            use str;
            use util;

            fn f() $b

            $($a)* #[test] fn green() { f() }
            $($a)* #[test] fn native() {
                use native;
                let (p, c) = Chan::new();
                native::task::spawn(proc() { c.send(f()) });
                p.recv();
            }
        }
    )
)

/// Get a port number, starting at 9600, for use in tests
pub fn next_test_port() -> u16 {
    static mut next_offset: AtomicUint = INIT_ATOMIC_UINT;
    unsafe {
        base_port() + next_offset.fetch_add(1, Relaxed) as u16
    }
}

/// Get a temporary path which could be the location of a unix socket
pub fn next_test_unix() -> Path {
    static mut COUNT: AtomicUint = INIT_ATOMIC_UINT;
    // base port and pid are an attempt to be unique between multiple
    // test-runners of different configurations running on one
    // buildbot, the count is to be unique within this executable.
    let string = format!("rust-test-unix-path-{}-{}-{}",
                         base_port(),
                         unsafe {libc::getpid()},
                         unsafe {COUNT.fetch_add(1, Relaxed)});
    if cfg!(unix) {
        os::tmpdir().join(string)
    } else {
        Path::new(r"\\.\pipe\" + string)
    }
}

/// Get a unique IPv4 localhost:port pair starting at 9600
pub fn next_test_ip4() -> SocketAddr {
    SocketAddr { ip: Ipv4Addr(127, 0, 0, 1), port: next_test_port() }
}

/// Get a unique IPv6 localhost:port pair starting at 9600
pub fn next_test_ip6() -> SocketAddr {
    SocketAddr { ip: Ipv6Addr(0, 0, 0, 0, 0, 0, 0, 1), port: next_test_port() }
}

/*
XXX: Welcome to MegaHack City.

The bots run multiple builds at the same time, and these builds
all want to use ports. This function figures out which workspace
it is running in and assigns a port range based on it.
*/
fn base_port() -> u16 {

    let base = 9600u16;
    let range = 1000u16;

    let bases = [
        ("32-opt", base + range * 1),
        ("32-nopt", base + range * 2),
        ("64-opt", base + range * 3),
        ("64-nopt", base + range * 4),
        ("64-opt-vg", base + range * 5),
        ("all-opt", base + range * 6),
        ("snap3", base + range * 7),
        ("dist", base + range * 8)
    ];

    // FIXME (#9639): This needs to handle non-utf8 paths
    let path = os::getcwd();
    let path_s = path.as_str().unwrap();

    let mut final_base = base;

    for &(dir, base) in bases.iter() {
        if path_s.contains(dir) {
            final_base = base;
            break;
        }
    }

    return final_base;
}

/// Raises the file descriptor limit when running tests if necessary
pub fn raise_fd_limit() {
    unsafe { darwin_fd_limit::raise_fd_limit() }
}

#[cfg(target_os="macos")]
#[allow(non_camel_case_types)]
mod darwin_fd_limit {
    /*!
     * darwin_fd_limit exists to work around an issue where launchctl on Mac OS X defaults the
     * rlimit maxfiles to 256/unlimited. The default soft limit of 256 ends up being far too low
     * for our multithreaded scheduler testing, depending on the number of cores available.
     *
     * This fixes issue #7772.
     */

    use libc;
    type rlim_t = libc::uint64_t;
    struct rlimit {
        rlim_cur: rlim_t,
        rlim_max: rlim_t
    }
    #[nolink]
    extern {
        // name probably doesn't need to be mut, but the C function doesn't specify const
        fn sysctl(name: *mut libc::c_int, namelen: libc::c_uint,
                  oldp: *mut libc::c_void, oldlenp: *mut libc::size_t,
                  newp: *mut libc::c_void, newlen: libc::size_t) -> libc::c_int;
        fn getrlimit(resource: libc::c_int, rlp: *mut rlimit) -> libc::c_int;
        fn setrlimit(resource: libc::c_int, rlp: *rlimit) -> libc::c_int;
    }
    static CTL_KERN: libc::c_int = 1;
    static KERN_MAXFILESPERPROC: libc::c_int = 29;
    static RLIMIT_NOFILE: libc::c_int = 8;

    pub unsafe fn raise_fd_limit() {
        // The strategy here is to fetch the current resource limits, read the kern.maxfilesperproc
        // sysctl value, and bump the soft resource limit for maxfiles up to the sysctl value.
        use ptr::mut_null;
        use mem::size_of_val;
        use os::last_os_error;

        // Fetch the kern.maxfilesperproc value
        let mut mib: [libc::c_int, ..2] = [CTL_KERN, KERN_MAXFILESPERPROC];
        let mut maxfiles: libc::c_int = 0;
        let mut size: libc::size_t = size_of_val(&maxfiles) as libc::size_t;
        if sysctl(&mut mib[0], 2, &mut maxfiles as *mut libc::c_int as *mut libc::c_void, &mut size,
                  mut_null(), 0) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling sysctl: {}", err);
            return;
        }

        // Fetch the current resource limits
        let mut rlim = rlimit{rlim_cur: 0, rlim_max: 0};
        if getrlimit(RLIMIT_NOFILE, &mut rlim) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling getrlimit: {}", err);
            return;
        }

        // Bump the soft limit to the smaller of kern.maxfilesperproc and the hard limit
        rlim.rlim_cur = ::cmp::min(maxfiles as rlim_t, rlim.rlim_max);

        // Set our newly-increased resource limit
        if setrlimit(RLIMIT_NOFILE, &rlim) != 0 {
            let err = last_os_error();
            error!("raise_fd_limit: error calling setrlimit: {}", err);
            return;
        }
    }
}

#[cfg(not(target_os="macos"))]
mod darwin_fd_limit {
    pub unsafe fn raise_fd_limit() {}
}
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Networking primitives for TCP/UDP communication.

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use sys_common::net as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener};
pub use self::udp::UdpSocket;
pub use self::parser::AddrParseError;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    #[stable(feature = "rust1", since = "1.0.0")]
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    #[stable(feature = "rust1", since = "1.0.0")]
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    #[stable(feature = "rust1", since = "1.0.0")]
    Both,
}

#[doc(hidden)]
trait NetInt {
    fn from_be(i: Self) -> Self;
    fn to_be(&self) -> Self;
}
macro_rules! doit {
    ($($t:ident)*) => ($(impl NetInt for $t {
        fn from_be(i: Self) -> Self { <$t>::from_be(i) }
        fn to_be(&self) -> Self { <$t>::to_be(*self) }
    })*)
}
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

fn hton<I: NetInt>(i: I) -> I { i.to_be() }
fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses")
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub struct LookupHost(net_imp::LookupHost);

#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// # #![feature(lookup_host)]
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}

/// Resolve the given address to a hostname.
///
/// This function may perform a DNS query to resolve `addr` and may also inspect
/// system configuration to resolve the specified address. If the address
/// cannot be resolved, it is returned in string format.
#[unstable(feature = "lookup_addr", reason = "recent addition")]
pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
    net_imp::lookup_addr(addr)
}
<commit_msg>Rollup merge of #25522 - alexcrichton:reexport-incoming, r=sfackler<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Networking primitives for TCP/UDP communication.

#![stable(feature = "rust1", since = "1.0.0")]

use prelude::v1::*;

use io::{self, Error, ErrorKind};
use sys_common::net as net_imp;

pub use self::ip::{IpAddr, Ipv4Addr, Ipv6Addr, Ipv6MulticastScope};
pub use self::addr::{SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs};
pub use self::tcp::{TcpStream, TcpListener, Incoming};
pub use self::udp::UdpSocket;
pub use self::parser::AddrParseError;

mod ip;
mod addr;
mod tcp;
mod udp;
mod parser;
#[cfg(test)] mod test;

/// Possible values which can be passed to the `shutdown` method of `TcpStream`
/// and `UdpSocket`.
#[derive(Copy, Clone, PartialEq, Debug)]
#[stable(feature = "rust1", since = "1.0.0")]
pub enum Shutdown {
    /// Indicates that the reading portion of this stream/socket should be shut
    /// down. All currently blocked and future reads will return `Ok(0)`.
    #[stable(feature = "rust1", since = "1.0.0")]
    Read,
    /// Indicates that the writing portion of this stream/socket should be shut
    /// down. All currently blocked and future writes will return an error.
    #[stable(feature = "rust1", since = "1.0.0")]
    Write,
    /// Shut down both the reading and writing portions of this stream.
    ///
    /// See `Shutdown::Read` and `Shutdown::Write` for more information.
    #[stable(feature = "rust1", since = "1.0.0")]
    Both,
}

#[doc(hidden)]
trait NetInt {
    fn from_be(i: Self) -> Self;
    fn to_be(&self) -> Self;
}
macro_rules! doit {
    ($($t:ident)*) => ($(impl NetInt for $t {
        fn from_be(i: Self) -> Self { <$t>::from_be(i) }
        fn to_be(&self) -> Self { <$t>::to_be(*self) }
    })*)
}
doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize }

fn hton<I: NetInt>(i: I) -> I { i.to_be() }
fn ntoh<I: NetInt>(i: I) -> I { I::from_be(i) }

fn each_addr<A: ToSocketAddrs, F, T>(addr: A, mut f: F) -> io::Result<T>
    where F: FnMut(&SocketAddr) -> io::Result<T>
{
    let mut last_err = None;
    for addr in try!(addr.to_socket_addrs()) {
        match f(&addr) {
            Ok(l) => return Ok(l),
            Err(e) => last_err = Some(e),
        }
    }
    Err(last_err.unwrap_or_else(|| {
        Error::new(ErrorKind::InvalidInput,
                   "could not resolve to any addresses")
    }))
}

/// An iterator over `SocketAddr` values returned from a host lookup operation.
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub struct LookupHost(net_imp::LookupHost);

#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
impl Iterator for LookupHost {
    type Item = io::Result<SocketAddr>;
    fn next(&mut self) -> Option<io::Result<SocketAddr>> { self.0.next() }
}

/// Resolve the host specified by `host` as a number of `SocketAddr` instances.
///
/// This method may perform a DNS query to resolve `host` and may also inspect
/// system configuration to resolve the specified hostname.
///
/// # Examples
///
/// ```no_run
/// # #![feature(lookup_host)]
/// use std::net;
///
/// # fn foo() -> std::io::Result<()> {
/// for host in try!(net::lookup_host("rust-lang.org")) {
///     println!("found address: {}", try!(host));
/// }
/// # Ok(())
/// # }
/// ```
#[unstable(feature = "lookup_host", reason = "unsure about the returned \
                                              iterator and returning socket \
                                              addresses")]
pub fn lookup_host(host: &str) -> io::Result<LookupHost> {
    net_imp::lookup_host(host).map(LookupHost)
}

/// Resolve the given address to a hostname.
///
/// This function may perform a DNS query to resolve `addr` and may also inspect
/// system configuration to resolve the specified address. If the address
/// cannot be resolved, it is returned in string format.
#[unstable(feature = "lookup_addr", reason = "recent addition")]
pub fn lookup_addr(addr: &IpAddr) -> io::Result<String> {
    net_imp::lookup_addr(addr)
}
<|endoftext|>


<commit_before>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<commit_msg>rollup merge of #19868: sourcefrog/master<commit_after>// Copyright 2013-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Interfaces to the operating system provided random number
//! generators.

pub use self::imp::OsRng;

#[cfg(all(unix, not(target_os = "ios")))]
mod imp {
    extern crate libc;

    use self::OsRngInner::*;

    use io::{IoResult, File};
    use path::Path;
    use rand::Rng;
    use rand::reader::ReaderRng;
    use result::Result::{Ok, Err};
    use slice::SliceExt;
    use mem;
    use os::errno;

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn getrandom(buf: &mut [u8]) -> libc::c_long {
        extern "C" {
            fn syscall(number: libc::c_long, ...) -> libc::c_long;
        }

        #[cfg(target_arch = "x86_64")]
        const NR_GETRANDOM: libc::c_long = 318;
        #[cfg(target_arch = "x86")]
        const NR_GETRANDOM: libc::c_long = 355;
        #[cfg(target_arch = "arm")]
        const NR_GETRANDOM: libc::c_long = 384;

        unsafe {
            syscall(NR_GETRANDOM, buf.as_mut_ptr(), buf.len(), 0u)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn getrandom(_buf: &mut [u8]) -> libc::c_long { -1 }

    fn getrandom_fill_bytes(v: &mut [u8]) {
        let mut read = 0;
        let len = v.len();
        while read < len {
            let result = getrandom(v[mut read..]);
            if result == -1 {
                let err = errno() as libc::c_int;
                if err == libc::EINTR {
                    continue;
                } else {
                    panic!("unexpected getrandom error: {}", err);
                }
            } else {
                read += result as uint;
            }
        }
    }

    fn getrandom_next_u32() -> u32 {
        let mut buf: [u8, ..4] = [0u8, ..4];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..4], u32>(buf) }
    }

    fn getrandom_next_u64() -> u64 {
        let mut buf: [u8, ..8] = [0u8, ..8];
        getrandom_fill_bytes(&mut buf);
        unsafe { mem::transmute::<[u8, ..8], u64>(buf) }
    }

    #[cfg(all(target_os = "linux",
              any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm")))]
    fn is_getrandom_available() -> bool {
        use sync::atomic::{AtomicBool, INIT_ATOMIC_BOOL, Relaxed};

        static GETRANDOM_CHECKED: AtomicBool = INIT_ATOMIC_BOOL;
        static GETRANDOM_AVAILABLE: AtomicBool = INIT_ATOMIC_BOOL;

        if !GETRANDOM_CHECKED.load(Relaxed) {
            let mut buf: [u8, ..0] = [];
            let result = getrandom(&mut buf);
            let available = if result == -1 {
                let err = errno() as libc::c_int;
                err != libc::ENOSYS
            } else {
                true
            };
            GETRANDOM_AVAILABLE.store(available, Relaxed);
            GETRANDOM_CHECKED.store(true, Relaxed);
            available
        } else {
            GETRANDOM_AVAILABLE.load(Relaxed)
        }
    }

    #[cfg(not(all(target_os = "linux",
                  any(target_arch = "x86_64", target_arch = "x86", target_arch = "arm"))))]
    fn is_getrandom_available() -> bool { false }

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        inner: OsRngInner,
    }

    enum OsRngInner {
        OsGetrandomRng,
        OsReaderRng(ReaderRng<File>),
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            if is_getrandom_available() {
                return Ok(OsRng { inner: OsGetrandomRng });
            }

            let reader = try!(File::open(&Path::new("/dev/urandom")));
            let reader_rng = ReaderRng::new(reader);

            Ok(OsRng { inner: OsReaderRng(reader_rng) })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u32(),
                OsReaderRng(ref mut rng) => rng.next_u32(),
            }
        }
        fn next_u64(&mut self) -> u64 {
            match self.inner {
                OsGetrandomRng => getrandom_next_u64(),
                OsReaderRng(ref mut rng) => rng.next_u64(),
            }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            match self.inner {
                OsGetrandomRng => getrandom_fill_bytes(v),
                OsReaderRng(ref mut rng) => rng.fill_bytes(v)
            }
        }
    }
}

#[cfg(target_os = "ios")]
mod imp {
    extern crate libc;

    use io::{IoResult};
    use kinds::marker;
    use mem;
    use os;
    use rand::Rng;
    use result::Result::{Ok};
    use self::libc::{c_int, size_t};
    use slice::SliceExt;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    #[allow(missing_copy_implementations)]
    pub struct OsRng {
        // dummy field to ensure that this struct cannot be constructed outside of this module
        _dummy: (),
    }

    #[repr(C)]
    struct SecRandom;

    #[allow(non_upper_case_globals)]
    static kSecRandomDefault: *const SecRandom = 0 as *const SecRandom;

    #[link(name = "Security", kind = "framework")]
    extern "C" {
        fn SecRandomCopyBytes(rnd: *const SecRandom,
                              count: size_t, bytes: *mut u8) -> c_int;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            Ok(OsRng { _dummy: () })
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                SecRandomCopyBytes(kSecRandomDefault, v.len() as size_t, v.as_mut_ptr())
            };
            if ret == -1 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(windows)]
mod imp {
    extern crate libc;

    use io::{IoResult, IoError};
    use mem;
    use ops::Drop;
    use os;
    use rand::Rng;
    use result::Result::{Ok, Err};
    use self::libc::{DWORD, BYTE, LPCSTR, BOOL};
    use self::libc::types::os::arch::extra::{LONG_PTR};
    use slice::SliceExt;

    type HCRYPTPROV = LONG_PTR;

    /// A random number generator that retrieves randomness straight from
    /// the operating system. Platform sources:
    ///
    /// - Unix-like systems (Linux, Android, Mac OSX): read directly from
    ///   `/dev/urandom`, or from `getrandom(2)` system call if available.
    /// - Windows: calls `CryptGenRandom`, using the default cryptographic
    ///   service provider with the `PROV_RSA_FULL` type.
    /// - iOS: calls SecRandomCopyBytes as /dev/(u)random is sandboxed.
    ///
    /// This does not block.
    pub struct OsRng {
        hcryptprov: HCRYPTPROV
    }

    static PROV_RSA_FULL: DWORD = 1;
    static CRYPT_SILENT: DWORD = 64;
    static CRYPT_VERIFYCONTEXT: DWORD = 0xF0000000;

    #[allow(non_snake_case)]
    extern "system" {
        fn CryptAcquireContextA(phProv: *mut HCRYPTPROV,
                                pszContainer: LPCSTR,
                                pszProvider: LPCSTR,
                                dwProvType: DWORD,
                                dwFlags: DWORD) -> BOOL;
        fn CryptGenRandom(hProv: HCRYPTPROV,
                          dwLen: DWORD,
                          pbBuffer: *mut BYTE) -> BOOL;
        fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) -> BOOL;
    }

    impl OsRng {
        /// Create a new `OsRng`.
        pub fn new() -> IoResult<OsRng> {
            let mut hcp = 0;
            let ret = unsafe {
                CryptAcquireContextA(&mut hcp, 0 as LPCSTR, 0 as LPCSTR,
                                     PROV_RSA_FULL,
                                     CRYPT_VERIFYCONTEXT | CRYPT_SILENT)
            };

            if ret == 0 {
                Err(IoError::last_error())
            } else {
                Ok(OsRng { hcryptprov: hcp })
            }
        }
    }

    impl Rng for OsRng {
        fn next_u32(&mut self) -> u32 {
            let mut v = [0u8, .. 4];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn next_u64(&mut self) -> u64 {
            let mut v = [0u8, .. 8];
            self.fill_bytes(&mut v);
            unsafe { mem::transmute(v) }
        }
        fn fill_bytes(&mut self, v: &mut [u8]) {
            let ret = unsafe {
                CryptGenRandom(self.hcryptprov, v.len() as DWORD,
                               v.as_mut_ptr())
            };
            if ret == 0 {
                panic!("couldn't generate random bytes: {}", os::last_os_error());
            }
        }
    }

    impl Drop for OsRng {
        fn drop(&mut self) {
            let ret = unsafe {
                CryptReleaseContext(self.hcryptprov, 0)
            };
            if ret == 0 {
                panic!("couldn't release context: {}", os::last_os_error());
            }
        }
    }
}

#[cfg(test)]
mod test {
    use prelude::*;

    use super::OsRng;
    use rand::Rng;
    use task;

    #[test]
    fn test_os_rng() {
        let mut r = OsRng::new().unwrap();

        r.next_u32();
        r.next_u64();

        let mut v = [0u8, .. 1000];
        r.fill_bytes(&mut v);
    }

    #[test]
    fn test_os_rng_tasks() {

        let mut txs = vec!();
        for _ in range(0u, 20) {
            let (tx, rx) = channel();
            txs.push(tx);
            task::spawn(move|| {
                // wait until all the tasks are ready to go.
                rx.recv();

                // deschedule to attempt to interleave things as much
                // as possible (XXX: is this a good test?)
                let mut r = OsRng::new().unwrap();
                task::deschedule();
                let mut v = [0u8, .. 1000];

                for _ in range(0u, 100) {
                    r.next_u32();
                    task::deschedule();
                    r.next_u64();
                    task::deschedule();
                    r.fill_bytes(&mut v);
                    task::deschedule();
                }
            })
        }

        // start all the tasks
        for tx in txs.iter() {
            tx.send(())
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Tyler Neely
//
// 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.
//

//! rustic merge operator
//!
//! ```
//! use rocksdb::{Options, DB, MergeOperands};
//!
//! fn concat_merge(new_key: &[u8],
//!                 existing_val: Option<&[u8]>,
//!                 operands: &mut MergeOperands)
//!                 -> Vec<u8> {
//!
//!    let mut result: Vec<u8> = Vec::with_capacity(operands.size_hint().0);
//!    existing_val.map(|v| {
//!        for e in v {
//!            result.push(*e)
//!        }
//!    });
//!    for op in operands {
//!        for e in op {
//!            result.push(*e)
//!        }
//!    }
//!    result
//! }
//!
//! fn main() {
//!    let path = "path/to/rocksdb";
//!    let mut opts = Options::default();
//!    opts.create_if_missing(true);
//!    opts.add_merge_operator("test operator", concat_merge);
//!    let db = DB::open(&opts, path).unwrap();
//!    let p = db.put(b"k1", b"a");
//!    db.merge(b"k1", b"b");
//!    db.merge(b"k1", b"c");
//!    db.merge(b"k1", b"d");
//!    db.merge(b"k1", b"efg");
//!    let r = db.get(b"k1");
//!    assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefg");
//! }
//! ```

use libc::{self, c_char, c_int, c_void, size_t};
use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice;

pub type MergeFn = fn(&[u8], Option<&[u8]>, &mut MergeOperands) -> Vec<u8>;

pub struct MergeOperatorCallback {
    pub name: CString,
    pub merge_fn: MergeFn,
}

pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) {
    let _: Box<MergeOperatorCallback> = mem::transmute(raw_cb);
}

pub unsafe extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    cb.name.as_ptr()
}

pub unsafe extern "C" fn full_merge_callback(raw_cb: *mut c_void,
                                             raw_key: *const c_char,
                                             key_len: size_t,
                                             existing_value: *const c_char,
                                             existing_value_len: size_t,
                                             operands_list: *const *const c_char,
                                             operands_list_len: *const size_t,
                                             num_operands: c_int,
                                             success: *mut u8,
                                             new_value_length: *mut size_t)
                                             -> *mut c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
    let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
    let oldval = slice::from_raw_parts(existing_value as *const u8, existing_value_len as usize);
    let mut result = (cb.merge_fn)(key, Some(oldval), operands);
    result.shrink_to_fit();
    // TODO(tan) investigate zero-copy techniques to improve performance
    let buf = libc::malloc(result.len() as size_t);
    assert!(!buf.is_null());
    *new_value_length = result.len() as size_t;
    *success = 1 as u8;
    ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
    buf as *mut c_char
}

pub unsafe extern "C" fn partial_merge_callback(raw_cb: *mut c_void,
                                                raw_key: *const c_char,
                                                key_len: size_t,
                                                operands_list: *const *const c_char,
                                                operands_list_len: *const size_t,
                                                num_operands: c_int,
                                                success: *mut u8,
                                                new_value_length: *mut size_t)
                                                -> *mut c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
    let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
    let mut result = (cb.merge_fn)(key, None, operands);
    result.shrink_to_fit();
    // TODO(tan) investigate zero-copy techniques to improve performance
    let buf = libc::malloc(result.len() as size_t);
    assert!(!buf.is_null());
    *new_value_length = 1 as size_t;
    *success = 1 as u8;
    ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
    buf as *mut c_char
}

pub struct MergeOperands {
    operands_list: *const *const c_char,
    operands_list_len: *const size_t,
    num_operands: usize,
    cursor: usize,
}

impl MergeOperands {
    fn new(operands_list: *const *const c_char,
           operands_list_len: *const size_t,
           num_operands: c_int)
           -> MergeOperands {
        assert!(num_operands >= 0);
        MergeOperands {
            operands_list: operands_list,
            operands_list_len: operands_list_len,
            num_operands: num_operands as usize,
            cursor: 0,
        }
    }
}

impl<'a> Iterator for &'a mut MergeOperands {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.cursor == self.num_operands {
            None
        } else {
            unsafe {
                let base = self.operands_list as usize;
                let base_len = self.operands_list_len as usize;
                let spacing = mem::size_of::<*const *const u8>();
                let spacing_len = mem::size_of::<*const size_t>();
                let len_ptr = (base_len + (spacing_len * self.cursor)) as *const size_t;
                let len = *len_ptr as usize;
                let ptr = base + (spacing * self.cursor);
                self.cursor += 1;
                Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) as *const u8,
                                                          len)))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.num_operands - self.cursor;
        (remaining, Some(remaining))
    }
}

#[cfg(test)]
#[allow(unused_variables)]
fn test_provided_merge(new_key: &[u8],
                       existing_val: Option<&[u8]>,
                       operands: &mut MergeOperands)
                       -> Vec<u8> {
    let nops = operands.size_hint().0;
    let mut result: Vec<u8> = Vec::with_capacity(nops);
    if let Some(v) = existing_val {
        for e in v {
            result.push(*e);
        }
    }
    for op in operands {
        for e in op {
            result.push(*e);
        }
    }
    result
}

#[test]
fn mergetest() {
    use Options;
    use rocksdb::DB;

    let path = "_rust_rocksdb_mergetest";
    let mut opts = Options::default();
    opts.create_if_missing(true);
    opts.set_merge_operator("test operator", test_provided_merge);
    {
        let db = DB::open(&opts, path).unwrap();
        let p = db.put(b"k1", b"a");
        assert!(p.is_ok());
        let _ = db.merge(b"k1", b"b");
        let _ = db.merge(b"k1", b"c");
        let _ = db.merge(b"k1", b"d");
        let _ = db.merge(b"k1", b"efg");
        let m = db.merge(b"k1", b"h");
        assert!(m.is_ok());
        match db.get(b"k1") {
            Ok(Some(value)) => {
                match value.to_utf8() {
                    Some(v) => println!("retrieved utf8 value: {}", v),
                    None => println!("did not read valid utf-8 out of the db"),
                }
            }
            Err(_) => println!("error reading value"),
            _ => panic!("value not present"),
        }

        assert!(m.is_ok());
        let r = db.get(b"k1");
        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefgh");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
    assert!(DB::destroy(&opts, path).is_ok());
}
<commit_msg>Fixed import for test.<commit_after>// Copyright 2014 Tyler Neely
//
// 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.
//

//! rustic merge operator
//!
//! ```
//! use rocksdb::{Options, DB, MergeOperands};
//!
//! fn concat_merge(new_key: &[u8],
//!                 existing_val: Option<&[u8]>,
//!                 operands: &mut MergeOperands)
//!                 -> Vec<u8> {
//!
//!    let mut result: Vec<u8> = Vec::with_capacity(operands.size_hint().0);
//!    existing_val.map(|v| {
//!        for e in v {
//!            result.push(*e)
//!        }
//!    });
//!    for op in operands {
//!        for e in op {
//!            result.push(*e)
//!        }
//!    }
//!    result
//! }
//!
//! fn main() {
//!    let path = "path/to/rocksdb";
//!    let mut opts = Options::default();
//!    opts.create_if_missing(true);
//!    opts.add_merge_operator("test operator", concat_merge);
//!    let db = DB::open(&opts, path).unwrap();
//!    let p = db.put(b"k1", b"a");
//!    db.merge(b"k1", b"b");
//!    db.merge(b"k1", b"c");
//!    db.merge(b"k1", b"d");
//!    db.merge(b"k1", b"efg");
//!    let r = db.get(b"k1");
//!    assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefg");
//! }
//! ```

use libc::{self, c_char, c_int, c_void, size_t};
use std::ffi::CString;
use std::mem;
use std::ptr;
use std::slice;

pub type MergeFn = fn(&[u8], Option<&[u8]>, &mut MergeOperands) -> Vec<u8>;

pub struct MergeOperatorCallback {
    pub name: CString,
    pub merge_fn: MergeFn,
}

pub unsafe extern "C" fn destructor_callback(raw_cb: *mut c_void) {
    let _: Box<MergeOperatorCallback> = mem::transmute(raw_cb);
}

pub unsafe extern "C" fn name_callback(raw_cb: *mut c_void) -> *const c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    cb.name.as_ptr()
}

pub unsafe extern "C" fn full_merge_callback(raw_cb: *mut c_void,
                                             raw_key: *const c_char,
                                             key_len: size_t,
                                             existing_value: *const c_char,
                                             existing_value_len: size_t,
                                             operands_list: *const *const c_char,
                                             operands_list_len: *const size_t,
                                             num_operands: c_int,
                                             success: *mut u8,
                                             new_value_length: *mut size_t)
                                             -> *mut c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
    let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
    let oldval = slice::from_raw_parts(existing_value as *const u8, existing_value_len as usize);
    let mut result = (cb.merge_fn)(key, Some(oldval), operands);
    result.shrink_to_fit();
    // TODO(tan) investigate zero-copy techniques to improve performance
    let buf = libc::malloc(result.len() as size_t);
    assert!(!buf.is_null());
    *new_value_length = result.len() as size_t;
    *success = 1 as u8;
    ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
    buf as *mut c_char
}

pub unsafe extern "C" fn partial_merge_callback(raw_cb: *mut c_void,
                                                raw_key: *const c_char,
                                                key_len: size_t,
                                                operands_list: *const *const c_char,
                                                operands_list_len: *const size_t,
                                                num_operands: c_int,
                                                success: *mut u8,
                                                new_value_length: *mut size_t)
                                                -> *mut c_char {
    let cb = &mut *(raw_cb as *mut MergeOperatorCallback);
    let operands = &mut MergeOperands::new(operands_list, operands_list_len, num_operands);
    let key = slice::from_raw_parts(raw_key as *const u8, key_len as usize);
    let mut result = (cb.merge_fn)(key, None, operands);
    result.shrink_to_fit();
    // TODO(tan) investigate zero-copy techniques to improve performance
    let buf = libc::malloc(result.len() as size_t);
    assert!(!buf.is_null());
    *new_value_length = 1 as size_t;
    *success = 1 as u8;
    ptr::copy(result.as_ptr() as *mut c_void, &mut *buf, result.len());
    buf as *mut c_char
}

pub struct MergeOperands {
    operands_list: *const *const c_char,
    operands_list_len: *const size_t,
    num_operands: usize,
    cursor: usize,
}

impl MergeOperands {
    fn new(operands_list: *const *const c_char,
           operands_list_len: *const size_t,
           num_operands: c_int)
           -> MergeOperands {
        assert!(num_operands >= 0);
        MergeOperands {
            operands_list: operands_list,
            operands_list_len: operands_list_len,
            num_operands: num_operands as usize,
            cursor: 0,
        }
    }
}

impl<'a> Iterator for &'a mut MergeOperands {
    type Item = &'a [u8];

    fn next(&mut self) -> Option<&'a [u8]> {
        if self.cursor == self.num_operands {
            None
        } else {
            unsafe {
                let base = self.operands_list as usize;
                let base_len = self.operands_list_len as usize;
                let spacing = mem::size_of::<*const *const u8>();
                let spacing_len = mem::size_of::<*const size_t>();
                let len_ptr = (base_len + (spacing_len * self.cursor)) as *const size_t;
                let len = *len_ptr as usize;
                let ptr = base + (spacing * self.cursor);
                self.cursor += 1;
                Some(mem::transmute(slice::from_raw_parts(*(ptr as *const *const u8) as *const u8,
                                                          len)))
            }
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        let remaining = self.num_operands - self.cursor;
        (remaining, Some(remaining))
    }
}

#[cfg(test)]
#[allow(unused_variables)]
fn test_provided_merge(new_key: &[u8],
                       existing_val: Option<&[u8]>,
                       operands: &mut MergeOperands)
                       -> Vec<u8> {
    let nops = operands.size_hint().0;
    let mut result: Vec<u8> = Vec::with_capacity(nops);
    if let Some(v) = existing_val {
        for e in v {
            result.push(*e);
        }
    }
    for op in operands {
        for e in op {
            result.push(*e);
        }
    }
    result
}

#[test]
fn mergetest() {
    use {DB, Options};

    let path = "_rust_rocksdb_mergetest";
    let mut opts = Options::default();
    opts.create_if_missing(true);
    opts.set_merge_operator("test operator", test_provided_merge);
    {
        let db = DB::open(&opts, path).unwrap();
        let p = db.put(b"k1", b"a");
        assert!(p.is_ok());
        let _ = db.merge(b"k1", b"b");
        let _ = db.merge(b"k1", b"c");
        let _ = db.merge(b"k1", b"d");
        let _ = db.merge(b"k1", b"efg");
        let m = db.merge(b"k1", b"h");
        assert!(m.is_ok());
        match db.get(b"k1") {
            Ok(Some(value)) => {
                match value.to_utf8() {
                    Some(v) => println!("retrieved utf8 value: {}", v),
                    None => println!("did not read valid utf-8 out of the db"),
                }
            }
            Err(_) => println!("error reading value"),
            _ => panic!("value not present"),
        }

        assert!(m.is_ok());
        let r = db.get(b"k1");
        assert!(r.unwrap().unwrap().to_utf8().unwrap() == "abcdefgh");
        assert!(db.delete(b"k1").is_ok());
        assert!(db.get(b"k1").unwrap().is_none());
    }
    assert!(DB::destroy(&opts, path).is_ok());
}
<|endoftext|>