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

use fall_tree::{File, Node, AstNode, Text};
use fall_tree::visitor::{Visitor, NodeVisitor};
use fall_tree::search::child_of_type;
use fall_tree::search::ast;

use {FallFile, SynRule, RefExpr, CallExpr, SYN_RULE};
use editor_api::{Diagnostic, Severity};

mod calls;
mod references;
mod diagnostics;
mod cache;

use self::diagnostics::DiagnosticSink;
use self::cache::{FileCache, NodeCache};
pub use self::calls::CallKind;
pub use self::references::RefKind;

pub struct Analysis<'f> {
    file: FallFile<'f>,

    diagnostics: Mutex<Vec<Diagnostic>>,

    used_rules: FileCache<HashSet<Node<'f>>>,
    contexts: FileCache<Vec<Text<'f>>>,

    calls: NodeCache<'f, Option<CallKind<'f>>>,
    refs: NodeCache<'f, Option<RefKind<'f>>>,
}

impl<'f> Analysis<'f> {
    pub fn new(file: FallFile) -> Analysis {
        Analysis {
            file,
            diagnostics: Default::default(),
            used_rules: Default::default(),
            contexts: Default::default(),
            calls: Default::default(),
            refs: Default::default(),
        }
    }

    pub fn file(&self) -> FallFile<'f> {
        self.file
    }

    pub fn is_unused(&self, rule: SynRule<'f>) -> bool {
        !self.used_rules().contains(&rule.node())
    }

    pub fn resolve_call(&self, call: CallExpr<'f>) -> Option<CallKind<'f>> {
        let mut diagnostics = Vec::new();
        let (value, committed) = {
            let mut sink = DiagnosticSink::new(&mut diagnostics);
            self.calls.get(call.node(), || {
                calls::resolve(self, &mut sink, call)
            })
        };
        if committed {
            self.diagnostics.lock().unwrap().extend(diagnostics)
        }
        value
    }

    pub fn resolve_reference(&self, ref_: RefExpr<'f>) -> Option<RefKind<'f>> {
        let mut diagnostics = Vec::new();
        let (value, committed) = {
            let mut sink = DiagnosticSink::new(&mut diagnostics);
            self.refs.get(ref_.node(), || {
                references::resolve(self, &mut sink, ref_)
            })
        };
        if committed {
            self.diagnostics.lock().unwrap().extend(diagnostics)
        }
        value
    }

    pub fn collect_all_diagnostics(&self) -> Vec<Diagnostic> {
        let mut result = Visitor(Vec::new())
            .visit::<RefExpr, _>(|_, ref_| { self.resolve_reference(ref_); })
            .visit::<CallExpr, _>(|_, call| { self.resolve_call(call); })
            .visit::<SynRule, _>(|acc, rule| {
                if self.is_unused(rule) {
                    if let Some(rule_name) = rule.name_ident() {
                        acc.push(Diagnostic {
                            range: rule_name.range(),
                            severity: Severity::Warning,
                            message: "Unused rule".to_string(),
                        })
                    }
                }
            })
            .walk_recursively_children_first(self.file().node());

        result.extend(self.diagnostics());
        result.sort_by_key(|d| (d.range.start(), d.range.end()));
        result
    }

    #[allow(unused)] // for debugging
    pub fn debug_diagnostics(&self) -> String {
        diagnostics::debug_diagnostics(&self.diagnostics(), self.file().node().text())
    }

    fn diagnostics(&self) -> Vec<Diagnostic> {
        self.diagnostics.lock().unwrap().clone()
    }

    fn contexts(&self) -> &[Text<'f>] {
        self.contexts.get(|| calls::contexts(self)).as_ref()
    }

    fn rule_by_name(&self, reference_name: Text<'f>) -> Option<SynRule<'f>> {
        self.file().syn_rules().find(|r| r.name() == Some(reference_name))
    }

    fn used_rules(&self) -> &HashSet<Node<'f>> {
        self.used_rules.get(|| self.calculate_used_rules())
    }

    fn calculate_used_rules(&self) -> HashSet<Node<'f>> {
        ast::descendants_of_type::<RefExpr>(self.file.node())
            .into_iter()
            .filter_map(|ref_| self.resolve_reference(ref_))
            .filter_map(|r| match r {
                RefKind::RuleReference(rule) => Some(rule.node()),
                _ => None
            })
            .chain(
                ast::descendants_of_type::<CallExpr>(self.file.node())
                    .into_iter()
                    .filter_map(|call| self.resolve_call(call))
                    .filter_map(|kind| match kind {
                        CallKind::RuleCall(rule, ..) => Some(rule.node()),
                        _ => None,
                    })
            )
            .chain(child_of_type(self.file.node(), SYN_RULE).into_iter())
            .collect()
    }
}

pub struct FileWithAnalysis {
    rent: rent::R
}

impl FileWithAnalysis {
    pub fn new(text: String) -> FileWithAnalysis {
        FileWithAnalysis::from_file(::parse(text))
    }

    fn from_file(file: File) -> FileWithAnalysis {
        FileWithAnalysis {
            rent: rent::R::new(Box::new(file), |file| {
                Analysis::new(FallFile::new(file.root()))
            })
        }
    }

    pub fn file(&self) -> &File {
        self.rent.head()
    }

    pub fn analyse<T, F: FnOnce(&Analysis) -> T>(&self, f: F) -> T {
        self.rent.rent(|a: &Analysis| f(a))
    }
}

rental! {
    mod rent {
        use super::*;

        #[rental]
        pub struct R {
            file: Box<File>,
            analysis: Analysis<'file>
        }
    }
}

#[cfg(test)]
fn check_diagnostics(code: &str, expected_diagnostics: &str) {
    use fall_tree::test_util::report_diff;
    let file = ::editor_api::analyse(code.to_string());

    file.analyse(|a| {
        let d = a.collect_all_diagnostics();
        let actual = d.into_iter().map(|d| {
            let s = match d.severity {
                Severity::Error => 'E',
                Severity::Warning => 'W',
            };
            format!("{}: {} {}", a.file().node().text().slice(d.range), s, d.message)
        }).collect::<Vec<_>>().join("\n");

        report_diff(&actual, expected_diagnostics);
    })
}

#[test]
fn test_diagnostics() {
    check_diagnostics(r"
       pub rule foo { <eof x> }
       rule bar { foo <abracadabra>}
       rule baz { <prev_is foo> <prev_is bar> <prev_is {foo}>}
    ", "\
<eof x>: E Wrong number of arguments, expected 0, got 1
x: E Unresolved reference
abracadabra: E Unresolved reference
baz: W Unused rule
<prev_is bar>: E <prev_is> arguments must be public rules
<prev_is {foo}>: E <prev_is> arguments must be public rules");
}
<commit_msg>Add sync test<commit_after>use std::collections::HashSet;
use std::sync::Mutex;

use fall_tree::{File, Node, AstNode, Text};
use fall_tree::visitor::{Visitor, NodeVisitor};
use fall_tree::search::child_of_type;
use fall_tree::search::ast;

use {FallFile, SynRule, RefExpr, CallExpr, SYN_RULE};
use editor_api::{Diagnostic, Severity};

mod calls;
mod references;
mod diagnostics;
mod cache;

use self::diagnostics::DiagnosticSink;
use self::cache::{FileCache, NodeCache};
pub use self::calls::CallKind;
pub use self::references::RefKind;

pub struct Analysis<'f> {
    file: FallFile<'f>,

    diagnostics: Mutex<Vec<Diagnostic>>,

    used_rules: FileCache<HashSet<Node<'f>>>,
    contexts: FileCache<Vec<Text<'f>>>,

    calls: NodeCache<'f, Option<CallKind<'f>>>,
    refs: NodeCache<'f, Option<RefKind<'f>>>,
}

impl<'f> Analysis<'f> {
    pub fn new(file: FallFile) -> Analysis {
        Analysis {
            file,
            diagnostics: Default::default(),
            used_rules: Default::default(),
            contexts: Default::default(),
            calls: Default::default(),
            refs: Default::default(),
        }
    }

    pub fn file(&self) -> FallFile<'f> {
        self.file
    }

    pub fn is_unused(&self, rule: SynRule<'f>) -> bool {
        !self.used_rules().contains(&rule.node())
    }

    pub fn resolve_call(&self, call: CallExpr<'f>) -> Option<CallKind<'f>> {
        let mut diagnostics = Vec::new();
        let (value, committed) = {
            let mut sink = DiagnosticSink::new(&mut diagnostics);
            self.calls.get(call.node(), || {
                calls::resolve(self, &mut sink, call)
            })
        };
        if committed {
            self.diagnostics.lock().unwrap().extend(diagnostics)
        }
        value
    }

    pub fn resolve_reference(&self, ref_: RefExpr<'f>) -> Option<RefKind<'f>> {
        let mut diagnostics = Vec::new();
        let (value, committed) = {
            let mut sink = DiagnosticSink::new(&mut diagnostics);
            self.refs.get(ref_.node(), || {
                references::resolve(self, &mut sink, ref_)
            })
        };
        if committed {
            self.diagnostics.lock().unwrap().extend(diagnostics)
        }
        value
    }

    pub fn collect_all_diagnostics(&self) -> Vec<Diagnostic> {
        let mut result = Visitor(Vec::new())
            .visit::<RefExpr, _>(|_, ref_| { self.resolve_reference(ref_); })
            .visit::<CallExpr, _>(|_, call| { self.resolve_call(call); })
            .visit::<SynRule, _>(|acc, rule| {
                if self.is_unused(rule) {
                    if let Some(rule_name) = rule.name_ident() {
                        acc.push(Diagnostic {
                            range: rule_name.range(),
                            severity: Severity::Warning,
                            message: "Unused rule".to_string(),
                        })
                    }
                }
            })
            .walk_recursively_children_first(self.file().node());

        result.extend(self.diagnostics());
        result.sort_by_key(|d| (d.range.start(), d.range.end()));
        result
    }

    #[allow(unused)] // for debugging
    pub fn debug_diagnostics(&self) -> String {
        diagnostics::debug_diagnostics(&self.diagnostics(), self.file().node().text())
    }

    fn diagnostics(&self) -> Vec<Diagnostic> {
        self.diagnostics.lock().unwrap().clone()
    }

    fn contexts(&self) -> &[Text<'f>] {
        self.contexts.get(|| calls::contexts(self)).as_ref()
    }

    fn rule_by_name(&self, reference_name: Text<'f>) -> Option<SynRule<'f>> {
        self.file().syn_rules().find(|r| r.name() == Some(reference_name))
    }

    fn used_rules(&self) -> &HashSet<Node<'f>> {
        self.used_rules.get(|| self.calculate_used_rules())
    }

    fn calculate_used_rules(&self) -> HashSet<Node<'f>> {
        ast::descendants_of_type::<RefExpr>(self.file.node())
            .into_iter()
            .filter_map(|ref_| self.resolve_reference(ref_))
            .filter_map(|r| match r {
                RefKind::RuleReference(rule) => Some(rule.node()),
                _ => None
            })
            .chain(
                ast::descendants_of_type::<CallExpr>(self.file.node())
                    .into_iter()
                    .filter_map(|call| self.resolve_call(call))
                    .filter_map(|kind| match kind {
                        CallKind::RuleCall(rule, ..) => Some(rule.node()),
                        _ => None,
                    })
            )
            .chain(child_of_type(self.file.node(), SYN_RULE).into_iter())
            .collect()
    }
}

pub struct FileWithAnalysis {
    rent: rent::R
}

impl FileWithAnalysis {
    pub fn new(text: String) -> FileWithAnalysis {
        FileWithAnalysis::from_file(::parse(text))
    }

    fn from_file(file: File) -> FileWithAnalysis {
        FileWithAnalysis {
            rent: rent::R::new(Box::new(file), |file| {
                Analysis::new(FallFile::new(file.root()))
            })
        }
    }

    pub fn file(&self) -> &File {
        self.rent.head()
    }

    pub fn analyse<T, F: FnOnce(&Analysis) -> T>(&self, f: F) -> T {
        self.rent.rent(|a: &Analysis| f(a))
    }
}

rental! {
    mod rent {
        use super::*;

        #[rental]
        pub struct R {
            file: Box<File>,
            analysis: Analysis<'file>
        }
    }
}

#[test]
fn analysis_is_sync() {
    fn assert_is_sync<T: Sync>() {}
    assert_is_sync::<Analysis>();
}

#[cfg(test)]
fn check_diagnostics(code: &str, expected_diagnostics: &str) {
    use fall_tree::test_util::report_diff;
    let file = ::editor_api::analyse(code.to_string());

    file.analyse(|a| {
        let d = a.collect_all_diagnostics();
        let actual = d.into_iter().map(|d| {
            let s = match d.severity {
                Severity::Error => 'E',
                Severity::Warning => 'W',
            };
            format!("{}: {} {}", a.file().node().text().slice(d.range), s, d.message)
        }).collect::<Vec<_>>().join("\n");

        report_diff(&actual, expected_diagnostics);
    })
}

#[test]
fn test_diagnostics() {
    check_diagnostics(r"
       pub rule foo { <eof x> }
       rule bar { foo <abracadabra>}
       rule baz { <prev_is foo> <prev_is bar> <prev_is {foo}>}
    ", "\
<eof x>: E Wrong number of arguments, expected 0, got 1
x: E Unresolved reference
abracadabra: E Unresolved reference
baz: W Unused rule
<prev_is bar>: E <prev_is> arguments must be public rules
<prev_is {foo}>: E <prev_is> arguments must be public rules");
}
<|endoftext|>


<commit_before>#[doc = "Operations and constants for `int`"];

#[cfg(target_arch="x86")]
const min_value: int = -1 << 31;

#[cfg(target_arch="x86_64")]
const min_value: int = -1 << 63;

// FIXME: Find another way to access the machine word size in a const expr
// (See Issue #2001)
#[cfg(target_arch="x86")]
const max_value: int = (-1 << 31)-1;

#[cfg(target_arch="x86_64")]
const max_value: int = (-1 << 63)-1;

pure fn min(x: int, y: int) -> int { if x < y { x } else { y } }
pure fn max(x: int, y: int) -> int { if x > y { x } else { y } }

pure fn add(x: int, y: int) -> int { ret x + y; }
pure fn sub(x: int, y: int) -> int { ret x - y; }
pure fn mul(x: int, y: int) -> int { ret x * y; }
pure fn div(x: int, y: int) -> int { ret x / y; }
pure fn rem(x: int, y: int) -> int { ret x % y; }

pure fn lt(x: int, y: int) -> bool { ret x < y; }
pure fn le(x: int, y: int) -> bool { ret x <= y; }
pure fn eq(x: int, y: int) -> bool { ret x == y; }
pure fn ne(x: int, y: int) -> bool { ret x != y; }
pure fn ge(x: int, y: int) -> bool { ret x >= y; }
pure fn gt(x: int, y: int) -> bool { ret x > y; }

pure fn positive(x: int) -> bool { ret x > 0; }
pure fn negative(x: int) -> bool { ret x < 0; }
pure fn nonpositive(x: int) -> bool { ret x <= 0; }
pure fn nonnegative(x: int) -> bool { ret x >= 0; }

// FIXME: Make sure this works with negative integers.
// See Issue #2002
#[doc = "Produce a uint suitable for use in a hash table"]
pure fn hash(x: int) -> uint { ret x as uint; }

#[doc = "Iterate over the range `[lo..hi)`"]
fn range(lo: int, hi: int, it: fn(int)) {
    let mut i = lo;
    while i < hi { it(i); i += 1; }
}

#[doc = "
Parse a buffer of bytes

# Arguments

* buf - A byte buffer
* radix - The base of the number
"]
fn parse_buf(buf: [u8], radix: uint) -> option<int> {
    if vec::len(buf) == 0u { ret none; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1;

    if buf[0] == ('-' as u8) {
        power = -1;
        start = 1u;
    }
    let mut n = 0;
    loop {
        alt char::to_digit(buf[i] as char, radix) {
          some(d) { n += (d as int) * power; }
          none { ret none; }
        }
        power *= radix as int;
        if i <= start { ret some(n); }
        i -= 1u;
    };
}

#[doc = "Parse a string to an int"]
fn from_str(s: str) -> option<int> { parse_buf(str::bytes(s), 10u) }

#[doc = "Convert to a string in a given base"]
fn to_str(n: int, radix: uint) -> str {
    assert (0u < radix && radix <= 16u);
    ret if n < 0 {
            "-" + uint::to_str(-n as uint, radix)
        } else { uint::to_str(n as uint, radix) };
}

#[doc = "Convert to a string"]
fn str(i: int) -> str { ret to_str(i, 10u); }

#[doc = "Returns `base` raised to the power of `exponent`"]
fn pow(base: int, exponent: uint) -> int {
    if exponent == 0u { ret 1; } //Not mathemtically true if [base == 0]
    if base     == 0  { ret 0; }
    let mut my_pow  = exponent;
    let mut acc     = 1;
    let mut multiplier = base;
    while(my_pow > 0u) {
      if my_pow % 2u == 1u {
         acc *= multiplier;
      }
      my_pow     /= 2u;
      multiplier *= multiplier;
    }
    ret acc;
}

#[doc = "Computes the bitwise complement"]
pure fn compl(i: int) -> int {
    uint::compl(i as uint) as int
}

#[doc = "Computes the absolute value"]
fn abs(i: int) -> int {
    if negative(i) { -i } else { i }
}

#[test]
fn test_from_str() {
    assert from_str("0") == some(0);
    assert from_str("3") == some(3);
    assert from_str("10") == some(10);
    assert from_str("123456789") == some(123456789);
    assert from_str("00100") == some(100);

    assert from_str("-1") == some(-1);
    assert from_str("-3") == some(-3);
    assert from_str("-10") == some(-10);
    assert from_str("-123456789") == some(-123456789);
    assert from_str("-00100") == some(-100);

    assert from_str(" ") == none;
    assert from_str("x") == none;
}

#[test]
fn test_parse_buf() {
    import str::bytes;
    assert parse_buf(bytes("123"), 10u) == some(123);
    assert parse_buf(bytes("1001"), 2u) == some(9);
    assert parse_buf(bytes("123"), 8u) == some(83);
    assert parse_buf(bytes("123"), 16u) == some(291);
    assert parse_buf(bytes("ffff"), 16u) == some(65535);
    assert parse_buf(bytes("FFFF"), 16u) == some(65535);
    assert parse_buf(bytes("z"), 36u) == some(35);
    assert parse_buf(bytes("Z"), 36u) == some(35);

    assert parse_buf(bytes("-123"), 10u) == some(-123);
    assert parse_buf(bytes("-1001"), 2u) == some(-9);
    assert parse_buf(bytes("-123"), 8u) == some(-83);
    assert parse_buf(bytes("-123"), 16u) == some(-291);
    assert parse_buf(bytes("-ffff"), 16u) == some(-65535);
    assert parse_buf(bytes("-FFFF"), 16u) == some(-65535);
    assert parse_buf(bytes("-z"), 36u) == some(-35);
    assert parse_buf(bytes("-Z"), 36u) == some(-35);

    assert parse_buf(str::bytes("Z"), 35u) == none;
    assert parse_buf(str::bytes("-9"), 2u) == none;
}

#[test]
fn test_to_str() {
    import str::eq;
    assert (eq(to_str(0, 10u), "0"));
    assert (eq(to_str(1, 10u), "1"));
    assert (eq(to_str(-1, 10u), "-1"));
    assert (eq(to_str(255, 16u), "ff"));
    assert (eq(to_str(100, 10u), "100"));
}

#[test]
fn test_pow() {
    assert (pow(0, 0u) == 1);
    assert (pow(0, 1u) == 0);
    assert (pow(0, 2u) == 0);
    assert (pow(-1, 0u) == 1);
    assert (pow(1, 0u) == 1);
    assert (pow(-3, 2u) == 9);
    assert (pow(-3, 3u) == -27);
    assert (pow(4, 9u) == 262144);
}

#[test]
fn test_overflows() {
   assert (max_value > 0);
   assert (min_value <= 0);
   assert (min_value + max_value + 1 == 0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>core: Remove a FIXME. Closes #2002<commit_after>#[doc = "Operations and constants for `int`"];

#[cfg(target_arch="x86")]
const min_value: int = -1 << 31;

#[cfg(target_arch="x86_64")]
const min_value: int = -1 << 63;

// FIXME: Find another way to access the machine word size in a const expr
// (See Issue #2001)
#[cfg(target_arch="x86")]
const max_value: int = (-1 << 31)-1;

#[cfg(target_arch="x86_64")]
const max_value: int = (-1 << 63)-1;

pure fn min(x: int, y: int) -> int { if x < y { x } else { y } }
pure fn max(x: int, y: int) -> int { if x > y { x } else { y } }

pure fn add(x: int, y: int) -> int { ret x + y; }
pure fn sub(x: int, y: int) -> int { ret x - y; }
pure fn mul(x: int, y: int) -> int { ret x * y; }
pure fn div(x: int, y: int) -> int { ret x / y; }
pure fn rem(x: int, y: int) -> int { ret x % y; }

pure fn lt(x: int, y: int) -> bool { ret x < y; }
pure fn le(x: int, y: int) -> bool { ret x <= y; }
pure fn eq(x: int, y: int) -> bool { ret x == y; }
pure fn ne(x: int, y: int) -> bool { ret x != y; }
pure fn ge(x: int, y: int) -> bool { ret x >= y; }
pure fn gt(x: int, y: int) -> bool { ret x > y; }

pure fn positive(x: int) -> bool { ret x > 0; }
pure fn negative(x: int) -> bool { ret x < 0; }
pure fn nonpositive(x: int) -> bool { ret x <= 0; }
pure fn nonnegative(x: int) -> bool { ret x >= 0; }

#[doc = "Produce a uint suitable for use in a hash table"]
pure fn hash(x: int) -> uint { ret x as uint; }

#[doc = "Iterate over the range `[lo..hi)`"]
fn range(lo: int, hi: int, it: fn(int)) {
    let mut i = lo;
    while i < hi { it(i); i += 1; }
}

#[doc = "
Parse a buffer of bytes

# Arguments

* buf - A byte buffer
* radix - The base of the number
"]
fn parse_buf(buf: [u8], radix: uint) -> option<int> {
    if vec::len(buf) == 0u { ret none; }
    let mut i = vec::len(buf) - 1u;
    let mut start = 0u;
    let mut power = 1;

    if buf[0] == ('-' as u8) {
        power = -1;
        start = 1u;
    }
    let mut n = 0;
    loop {
        alt char::to_digit(buf[i] as char, radix) {
          some(d) { n += (d as int) * power; }
          none { ret none; }
        }
        power *= radix as int;
        if i <= start { ret some(n); }
        i -= 1u;
    };
}

#[doc = "Parse a string to an int"]
fn from_str(s: str) -> option<int> { parse_buf(str::bytes(s), 10u) }

#[doc = "Convert to a string in a given base"]
fn to_str(n: int, radix: uint) -> str {
    assert (0u < radix && radix <= 16u);
    ret if n < 0 {
            "-" + uint::to_str(-n as uint, radix)
        } else { uint::to_str(n as uint, radix) };
}

#[doc = "Convert to a string"]
fn str(i: int) -> str { ret to_str(i, 10u); }

#[doc = "Returns `base` raised to the power of `exponent`"]
fn pow(base: int, exponent: uint) -> int {
    if exponent == 0u { ret 1; } //Not mathemtically true if [base == 0]
    if base     == 0  { ret 0; }
    let mut my_pow  = exponent;
    let mut acc     = 1;
    let mut multiplier = base;
    while(my_pow > 0u) {
      if my_pow % 2u == 1u {
         acc *= multiplier;
      }
      my_pow     /= 2u;
      multiplier *= multiplier;
    }
    ret acc;
}

#[doc = "Computes the bitwise complement"]
pure fn compl(i: int) -> int {
    uint::compl(i as uint) as int
}

#[doc = "Computes the absolute value"]
fn abs(i: int) -> int {
    if negative(i) { -i } else { i }
}

#[test]
fn test_from_str() {
    assert from_str("0") == some(0);
    assert from_str("3") == some(3);
    assert from_str("10") == some(10);
    assert from_str("123456789") == some(123456789);
    assert from_str("00100") == some(100);

    assert from_str("-1") == some(-1);
    assert from_str("-3") == some(-3);
    assert from_str("-10") == some(-10);
    assert from_str("-123456789") == some(-123456789);
    assert from_str("-00100") == some(-100);

    assert from_str(" ") == none;
    assert from_str("x") == none;
}

#[test]
fn test_parse_buf() {
    import str::bytes;
    assert parse_buf(bytes("123"), 10u) == some(123);
    assert parse_buf(bytes("1001"), 2u) == some(9);
    assert parse_buf(bytes("123"), 8u) == some(83);
    assert parse_buf(bytes("123"), 16u) == some(291);
    assert parse_buf(bytes("ffff"), 16u) == some(65535);
    assert parse_buf(bytes("FFFF"), 16u) == some(65535);
    assert parse_buf(bytes("z"), 36u) == some(35);
    assert parse_buf(bytes("Z"), 36u) == some(35);

    assert parse_buf(bytes("-123"), 10u) == some(-123);
    assert parse_buf(bytes("-1001"), 2u) == some(-9);
    assert parse_buf(bytes("-123"), 8u) == some(-83);
    assert parse_buf(bytes("-123"), 16u) == some(-291);
    assert parse_buf(bytes("-ffff"), 16u) == some(-65535);
    assert parse_buf(bytes("-FFFF"), 16u) == some(-65535);
    assert parse_buf(bytes("-z"), 36u) == some(-35);
    assert parse_buf(bytes("-Z"), 36u) == some(-35);

    assert parse_buf(str::bytes("Z"), 35u) == none;
    assert parse_buf(str::bytes("-9"), 2u) == none;
}

#[test]
fn test_to_str() {
    import str::eq;
    assert (eq(to_str(0, 10u), "0"));
    assert (eq(to_str(1, 10u), "1"));
    assert (eq(to_str(-1, 10u), "-1"));
    assert (eq(to_str(255, 16u), "ff"));
    assert (eq(to_str(100, 10u), "100"));
}

#[test]
fn test_pow() {
    assert (pow(0, 0u) == 1);
    assert (pow(0, 1u) == 0);
    assert (pow(0, 2u) == 0);
    assert (pow(-1, 0u) == 1);
    assert (pow(1, 0u) == 1);
    assert (pow(-3, 2u) == 9);
    assert (pow(-3, 3u) == -27);
    assert (pow(4, 9u) == 262144);
}

#[test]
fn test_overflows() {
   assert (max_value > 0);
   assert (min_value <= 0);
   assert (min_value + max_value + 1 == 0);
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|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.

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use clone::Clone;
use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: usize,
}

impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
    fn clone(&self) -> Slice<T> { *self }
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Trait Objects chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/trait-objects.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SometTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub unsafe trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

unsafe impl<T> Repr<Slice<T>> for [T] {}
unsafe impl Repr<Slice<u8>> for str {}
<commit_msg>Rollup merge of #24700 - rkruppe:doc-typos, r=alexcrichton<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.

#![allow(missing_docs)]
#![unstable(feature = "core")]

//! Contains struct definitions for the layout of compiler built-in types.
//!
//! They can be used as targets of transmutes in unsafe code for manipulating
//! the raw representations directly.
//!
//! Their definition should always match the ABI defined in `rustc::back::abi`.

use clone::Clone;
use marker::Copy;
use mem;

/// The representation of a slice like `&[T]`.
///
/// This struct is guaranteed to have the layout of types like `&[T]`,
/// `&str`, and `Box<[T]>`, but is not the type of such slices
/// (e.g. the fields are not directly accessible on a `&[T]`) nor does
/// it control that layout (changing the definition will not change
/// the layout of a `&[T]`). It is only designed to be used by unsafe
/// code that needs to manipulate the low-level details.
///
/// However, it is not recommended to use this type for such code,
/// since there are alternatives which may be safer:
///
/// - Creating a slice from a data pointer and length can be done with
///   `std::slice::from_raw_parts` or `std::slice::from_raw_parts_mut`
///   instead of `std::mem::transmute`ing a value of type `Slice`.
/// - Extracting the data pointer and length from a slice can be
///   performed with the `as_ptr` (or `as_mut_ptr`) and `len`
///   methods.
///
/// If one does decide to convert a slice value to a `Slice`, the
/// `Repr` trait in this module provides a method for a safe
/// conversion from `&[T]` (and `&str`) to a `Slice`, more type-safe
/// than a call to `transmute`.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::raw::{self, Repr};
///
/// let slice: &[u16] = &[1, 2, 3, 4];
///
/// let repr: raw::Slice<u16> = slice.repr();
/// println!("data pointer = {:?}, length = {}", repr.data, repr.len);
/// ```
#[repr(C)]
pub struct Slice<T> {
    pub data: *const T,
    pub len: usize,
}

impl<T> Copy for Slice<T> {}
impl<T> Clone for Slice<T> {
    fn clone(&self) -> Slice<T> { *self }
}

/// The representation of a trait object like `&SomeTrait`.
///
/// This struct has the same layout as types like `&SomeTrait` and
/// `Box<AnotherTrait>`. The [Trait Objects chapter of the
/// Book][moreinfo] contains more details about the precise nature of
/// these internals.
///
/// [moreinfo]: ../../book/trait-objects.html#representation
///
/// `TraitObject` is guaranteed to match layouts, but it is not the
/// type of trait objects (e.g. the fields are not directly accessible
/// on a `&SomeTrait`) nor does it control that layout (changing the
/// definition will not change the layout of a `&SomeTrait`). It is
/// only designed to be used by unsafe code that needs to manipulate
/// the low-level details.
///
/// There is no `Repr` implementation for `TraitObject` because there
/// is no way to refer to all trait objects generically, so the only
/// way to create values of this type is with functions like
/// `std::mem::transmute`. Similarly, the only way to create a true
/// trait object from a `TraitObject` value is with `transmute`.
///
/// Synthesizing a trait object with mismatched types—one where the
/// vtable does not correspond to the type of the value to which the
/// data pointer points—is highly likely to lead to undefined
/// behaviour.
///
/// # Examples
///
/// ```
/// # #![feature(core)]
/// use std::mem;
/// use std::raw;
///
/// // an example trait
/// trait Foo {
///     fn bar(&self) -> i32;
/// }
/// impl Foo for i32 {
///     fn bar(&self) -> i32 {
///          *self + 1
///     }
/// }
///
/// let value: i32 = 123;
///
/// // let the compiler make a trait object
/// let object: &Foo = &value;
///
/// // look at the raw representation
/// let raw_object: raw::TraitObject = unsafe { mem::transmute(object) };
///
/// // the data pointer is the address of `value`
/// assert_eq!(raw_object.data as *const i32, &value as *const _);
///
///
/// let other_value: i32 = 456;
///
/// // construct a new object, pointing to a different `i32`, being
/// // careful to use the `i32` vtable from `object`
/// let synthesized: &Foo = unsafe {
///      mem::transmute(raw::TraitObject {
///          data: &other_value as *const _ as *mut (),
///          vtable: raw_object.vtable
///      })
/// };
///
/// // it should work just like we constructed a trait object out of
/// // `other_value` directly
/// assert_eq!(synthesized.bar(), 457);
/// ```
#[repr(C)]
#[derive(Copy, Clone)]
pub struct TraitObject {
    pub data: *mut (),
    pub vtable: *mut (),
}

/// This trait is meant to map equivalences between raw structs and their
/// corresponding rust values.
pub unsafe trait Repr<T> {
    /// This function "unwraps" a rust value (without consuming it) into its raw
    /// struct representation. This can be used to read/write different values
    /// for the struct. This is a safe method because by default it does not
    /// enable write-access to the fields of the return value in safe code.
    #[inline]
    fn repr(&self) -> T { unsafe { mem::transmute_copy(&self) } }
}

unsafe impl<T> Repr<Slice<T>> for [T] {}
unsafe impl Repr<Slice<u8>> for str {}
<|endoftext|>


<commit_before>pub mod proc_pid;
pub mod kmesg_buffer;
pub mod work_queue_info;
pub mod thread_info;
pub mod task_info;
pub mod bsd_info;
pub mod pid_rusage;
pub mod file_info;

#[cfg(target_os = "macos")]
pub mod net_info;

mod helpers;<commit_msg>Only include modules that make sense on macos<commit_after>pub mod proc_pid;
pub mod kmesg_buffer;
#[cfg(target_os = "macos")]
pub mod work_queue_info;
#[cfg(target_os = "macos")]
pub mod thread_info;
#[cfg(target_os = "macos")]
pub mod task_info;
#[cfg(target_os = "macos")]
pub mod bsd_info;
pub mod pid_rusage;
pub mod file_info;

#[cfg(target_os = "macos")]
pub mod net_info;

mod helpers;<|endoftext|>


<commit_before>use bifrost::utils::fut_exec::wait;
use client::AsyncClient;
use dovahkiin::types::custom_types::bytes::SmallBytes;
use dovahkiin::types::custom_types::id::Id;
use dovahkiin::types::custom_types::map::Map;
use dovahkiin::types::type_id_of;
use dovahkiin::types::value::ToValue;
use futures::prelude::*;
use index::*;
use itertools::Itertools;
use owning_ref::OwningHandle;
use parking_lot::Mutex;
use parking_lot::RwLock;
use parking_lot::RwLockReadGuard;
use ram::cell::Cell;
use ram::schema::Field;
use ram::schema::Schema;
use ram::types::*;
use std::cell::RefCell;
use std::collections::btree_map::Range;
use std::collections::hash_map::DefaultHasher;
use std::collections::{BTreeMap, BTreeSet, LinkedList};
use std::fmt::Debug;
use std::marker::PhantomData;
use std::mem;
use std::ops::Bound::*;
use std::ops::RangeBounds;
use std::rc::Rc;
use std::sync::atomic::{AtomicUsize, Ordering::Relaxed};
use std::sync::Arc;
use utils::lru_cache::LRUCache;

// LevelTree items cannot been added or removed individually
// Items must been merged from higher level in bulk
// Deletion will be performed when merging to or from higher level tree
// Because tree update will not to be performed in parallel. Unlike memtable, a single r/w lock
// should be sufficient. Thus concurrency control will be simple and efficient.

type TombstonesInner = BTreeSet<EntryKey>;
type Tombstones = RwLock<TombstonesInner>;
type PageCache<S> = Arc<Mutex<LRUCache<Id, Arc<SSPage<S>>>>>;
type PageIndex = Arc<RwLock<BTreeMap<EntryKey, Id>>>;
type IndexHandle<'a> = OwningHandle<PageIndex, RwLockReadGuard<'a, BTreeMap<EntryKey, Id>>>;

const PAGE_SCHEMA: &'static str = "NEB_SSTABLE_PAGE";

lazy_static! {
    static ref PAGE_SCHEMA_ID: u32 = key_hash(PAGE_SCHEMA) as u32;
}

pub struct LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    neb_client: Arc<AsyncClient>,
    index: PageIndex,
    tombstones: Tombstones,
    pages: PageCache<S>,
    marker: PhantomData<S>,
    len: AtomicUsize,
}
struct SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    id: Id,
    slice: S,
    len: usize,
}

impl<S> SSPage<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pub fn from_cell(cell: Cell) -> Self {
        let mut slice = S::init();
        let slice_len = slice.as_slice().len();
        let cell_id = cell.id();
        let keys = cell.data;
        let keys_len = keys.len().unwrap();
        let keys_array = if let Value::PrimArray(PrimitiveArray::SmallBytes(ref array)) = keys {
            array
        } else {
            panic!()
        };
        for (i, val) in keys_array.iter().enumerate() {
            slice.as_slice()[i] = EntryKey::from(val.as_slice());
        }
        Self {
            id: cell_id,
            slice,
            len: keys_array.len(),
        }
    }

    pub fn to_cell(&self) -> Cell {
        let value = self
            .slice
            .as_slice_immute()
            .iter()
            .map(|key| SmallBytes::from_vec(key.as_slice().to_vec()))
            .take(self.len)
            .collect_vec()
            .value();
        Cell::new_with_id(*PAGE_SCHEMA_ID, &self.id, value)
    }

    pub fn new() -> Self {
        SSPage {
            slice: S::init(),
            id: Id::unit_id(),
            len: 0,
        }
    }
}

pub trait Tree: MergeableTree {
    fn seek(&self, key: &EntryKey, ordering: Ordering) -> Box<Cursor>;
    fn merge(&self, source: &mut [EntryKey], source_tombstones: &mut TombstonesInner);
    fn mark_deleted(&self, key: &EntryKey) -> bool;
    fn is_deleted(&self, key: &EntryKey) -> bool;
    fn len(&self) -> usize;
}

impl<S> LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    pub fn new(neb_client: &Arc<AsyncClient>) -> Self {
        let client = neb_client.clone();
        let mut index = Arc::new(RwLock::new(BTreeMap::new()));
        Self {
            neb_client: neb_client.clone(),
            index,
            tombstones: Tombstones::new(BTreeSet::new()),
            len: AtomicUsize::new(0),
            // TODO: carefully set the capacity
            pages: Arc::new(Mutex::new(LRUCache::new(
                100,
                move |id| {
                    client
                        .read_cell(*id)
                        .wait()
                        .unwrap()
                        .map(|cell| Arc::new(SSPage::from_cell(cell)))
                        .ok()
                },
                |_, _| {
                    // will do nothing on evict for pages will be write to back storage once updated
                },
            ))),
            marker: PhantomData {},
        }
    }
}

impl<S> Tree for LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    fn seek(&self, key: &EntryKey, ordering: Ordering) -> Box<Cursor> {
        let index = self.index.read();
        debug!("Seeking for {:?}, in index len {}", key, index.len());
        let mut range = match ordering {
            Ordering::Forward => index.range::<EntryKey, _>(key..),
            Ordering::Backward => index.range::<EntryKey, _>(..=key),
        };
        let first = match ordering {
            Ordering::Forward => range.next(),
            Ordering::Backward => range.next_back(),
        }
        .map(|(_, page_id)| {
            debug!("First page id is {:?}", page_id);
            self.pages.lock().get_or_fetch(page_id).unwrap().clone()
        });

        let (pos, page_len) = if let Some(ref page) = first {
            debug!("First page has {} elements", page.len);
            (
                page.slice.as_slice_immute()[..page.len]
                    .binary_search(key)
                    .unwrap_or_else(|i| i),
                page.len,
            )
        } else {
            (0, 0)
        };

        debug!("First page search pos is {}", pos);

        let mut cursor = RTCursor {
            ordering,
            page_len,
            current: first,
            pos,
            cache: self.pages.clone(),
            index: self.index.clone(),
        };

        if cursor.current.is_some() {
            match ordering {
                Ordering::Forward => {
                    if pos >= page_len {
                        cursor.next();
                    }
                }
                Ordering::Backward => {}
            }
        }

        box cursor
    }

    fn merge(&self, source: &mut [EntryKey], source_tombstones: &mut TombstonesInner) {
        let mut target_tombstones = self.tombstones.write();
        let mut pages_cache = self.pages.lock();
        let mut index = self.index.write();
        let mut num_new_merged = 0;
        let (keys_to_removed, mut merged, mut ids_to_reuse) = {
            let (target_keys, target_pages): (Vec<_>, Vec<_>) = {
                let first = source.first().unwrap();
                let last = source.last().unwrap();
                index
                    .range::<EntryKey, _>(first..=last)
                    .map(|(k, id)| (k, pages_cache.get_or_fetch(id).unwrap().clone()))
                    .unzip()
            };
            let mut merged: Vec<SSPage<S>> = vec![SSPage::new()];
            let page_size = merged[0].slice.len();
            let target_page_ids = target_pages.iter().map(|p| p.id).collect::<LinkedList<_>>();
            let mut target = target_pages
                .iter()
                .map(|page| &page.slice.as_slice_immute()[..page.len])
                .flat_map(|x| x)
                .map(|x| (*x).clone())
                .collect_vec();

            let src_len = source.len();
            let tgt_len = target.len();

            debug!("Src len {}, target len {}", src_len, tgt_len);

            let mut srci = 0;
            let mut tgti = 0;

            while srci < src_len || tgti < tgt_len {
                let mut from_source = false;
                let mut lowest: &mut EntryKey = if srci >= src_len {
                    // source overflowed
                    tgti += 1;
                    &mut target[tgti - 1]
                } else if tgti >= tgt_len {
                    // target overflowed
                    srci += 1;
                    from_source = true;
                    &mut source[srci - 1]
                } else {
                    // normal case, compare
                    let t = &mut target[tgti];
                    let s = &mut source[srci];
                    if t <= s {
                        tgti += 1;
                        t
                    } else {
                        srci += 1;
                        from_source = true;
                        s
                    }
                };

                if from_source {
                    if source_tombstones.remove(lowest) {
                        continue;
                    }
                } else {
                    if target_tombstones.remove(lowest) {
                        continue;
                    }
                }

                if from_source {
                    target_tombstones.remove(lowest);
                    num_new_merged += 1;
                }

                let merging_page_len = {
                    let merging_page = merged.last_mut().unwrap();
                    let page_len = merging_page.len;
                    debug!("i is {}, picking {:?}", page_len, lowest);
                    mem::swap(&mut merging_page.slice.as_slice()[page_len], lowest);
                    merging_page.len += 1;
                    merging_page.len
                };

                if merging_page_len >= page_size {
                    merged.push(SSPage::new());
                }
            }
            if merged.last().unwrap().len == 0 {
                let merged_len = merged.len();
                merged.remove(merged_len - 1);
            }
            (
                target_keys.into_iter().map(|x| x.clone()).collect_vec(),
                merged,
                target_page_ids,
            )
        };

        debug!("Merged {} pages", merged.len());

        for k in keys_to_removed {
            debug!("Remove stale page index {:?}", k);
            index.remove(&k).unwrap();
        }

        for id in &ids_to_reuse {
            debug!("Remove stale page cache {:?}", id);
            pages_cache.remove(id);
        }

        for mut page in merged {
            let reuse_id = ids_to_reuse.pop_back();
            let id = reuse_id.unwrap_or_else(|| Id::rand());
            let index_key = page.slice.as_slice_immute()[0].clone();
            page.id = id;
            let cell = page.to_cell();
            if reuse_id.is_some() {
                debug!("Reuse page id by updating {:?}", cell.id());
                self.neb_client.update_cell(cell).wait().unwrap();
            } else {
                debug!("Inserting page with id {:?}", cell.id());
                self.neb_client.write_cell(cell).wait().unwrap();
            }

            debug!("Insert page index key {:?}, id {:?}", index_key, id);
            index.insert(index_key, id);
        }
        self.len.fetch_add(num_new_merged, Relaxed);
    }

    fn mark_deleted(&self, key: &EntryKey) -> bool {
        if self.seek(key, Ordering::Forward).current() == Some(key) {
            let mut tombstones = self.tombstones.write();
            if tombstones.contains(key) {
                return false;
            } else {
                tombstones.insert(key.clone());
                self.len.fetch_sub(1, Relaxed);
                return true;
            }
        }
        false
    }

    fn is_deleted(&self, key: &EntryKey) -> bool {
        self.tombstones.read().contains(key)
    }

    fn len(&self) -> usize {
        self.len.load(Relaxed)
    }
}

impl<S> MergeableTree for LevelTree<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    fn prepare_level_merge(&self) -> Box<MergingTreeGuard> {
        box LevelTreeMergeGuard {
            index: self.index.clone(),
            pages: self.pages.clone(),
        }
    }
}

pub struct LevelMergingPage<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    index: PageIndex,
    page: Arc<SSPage<S>>,
    page_cache: PageCache<S>,
    lock: IndexHandle<'a>,
}

impl<'a, S> MergingPage for LevelMergingPage<'a, S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    fn next(&self) -> Box<MergingPage> {
        let index = OwningHandle::new_with_fn(self.index.clone(), |x| unsafe { &*x }.read());
        let page = {
            let current_last = self.page.slice.as_slice_immute().first().unwrap();
            let (_, page_id) = index.range::<EntryKey, _>(..current_last).last().unwrap();
            self.page_cache
                .lock()
                .get_or_fetch(page_id)
                .unwrap()
                .clone()
        };
        box LevelMergingPage {
            page,
            lock: index,
            index: self.index.clone(),
            page_cache: self.page_cache.clone(),
        }
    }

    fn keys(&self) -> &[EntryKey] {
        &self.page.slice.as_slice_immute()[..self.page.len]
    }
}

pub struct LevelTreeMergeGuard<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    index: PageIndex,
    pages: PageCache<S>,
}

impl<S> MergingTreeGuard for LevelTreeMergeGuard<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice + 'static,
{
    fn remove_pages(&self, pages: &[&[EntryKey]]) {
        let mut index = self.index.write();
        pages
            .iter()
            .map(|page| page.first().unwrap())
            .for_each(|page_index| {
                index.remove(page_index);
            });
    }

    fn last_page(&self) -> Box<MergingPage> {
        let index = OwningHandle::new_with_fn(self.index.clone(), |x| unsafe { &*x }.read());
        let page = {
            let (_, page_id) = index.iter().last().unwrap();
            self.pages.lock().get_or_fetch(page_id).unwrap().clone()
        };
        box LevelMergingPage {
            page,
            lock: index,
            index: self.index.clone(),
            page_cache: self.pages.clone(),
        }
    }
}

pub trait SortableEntrySlice: Sized + Slice<Item = EntryKey> {}

pub struct RTCursor<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    pos: usize,
    ordering: Ordering,
    page_len: usize,
    current: Option<Arc<SSPage<S>>>,
    cache: PageCache<S>,
    index: PageIndex,
}

impl<S> Cursor for RTCursor<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    fn next(&mut self) -> bool {
        if self.current.is_some() {
            match self.ordering {
                Ordering::Forward => {
                    if self.pos + 1 >= self.page_len {
                        let current_key = self.current().unwrap().clone();
                        if let Some((_, page_id)) = self
                            .index
                            .read()
                            .range::<EntryKey, _>((Excluded(&current_key), Unbounded))
                            .next()
                        {
                            let next_page = self.get_page(page_id);
                            self.pos = next_page
                                .slice
                                .as_slice_immute()
                                .binary_search(&current_key)
                                .map(|i| if i < self.page_len - 1 { i + 1 } else { i })
                                .unwrap_or_else(|i| i);
                            self.current = Some(next_page);
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.pos += 1;
                    }
                }
                Ordering::Backward => {
                    if self.pos == 0 {
                        let current_key = self.current().unwrap().clone();
                        if let Some((_, page_id)) = self
                            .index
                            .read()
                            .range::<EntryKey, _>((Unbounded, Excluded(&current_key)))
                            .next_back()
                        {
                            let next_page = self.get_page(page_id);
                            self.pos = next_page
                                .slice
                                .as_slice_immute()
                                .binary_search(&current_key)
                                .map(|i| if i != 0 { i - 1 } else { i })
                                .unwrap_or_else(|i| i);
                            self.current = Some(next_page);
                        } else {
                            self.current = None;
                            return false;
                        }
                    } else {
                        self.pos -= 1;
                    }
                }
            }
            true
        } else {
            false
        }
    }

    fn current(&self) -> Option<&EntryKey> {
        if self.pos < 0 || self.pos >= self.page_len {
            return None;
        }
        if let Some(ref page) = self.current {
            Some(&page.slice.as_slice_immute()[self.pos])
        } else {
            None
        }
    }
}

impl<S> RTCursor<S>
where
    S: Slice<Item = EntryKey> + SortableEntrySlice,
{
    fn get_page(&self, id: &Id) -> Arc<SSPage<S>> {
        self.cache.lock().get_or_fetch(id).unwrap().clone()
    }
}

pub fn get_schema() -> Schema {
    Schema {
        id: *PAGE_SCHEMA_ID,
        name: String::from(PAGE_SCHEMA),
        key_field: None,
        str_key_field: None,
        is_dynamic: false,
        fields: Field::new("*", type_id_of(Type::SmallBytes), false, true, None),
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use client;
    use futures::prelude::*;
    use index::sstable::LevelTree;
    use server::NebServer;
    use server::ServerOptions;
    use std::ptr;
    use std::sync::Arc;

    type SmallPage = [EntryKey; 5];

    impl_sspage_slice!(SmallPage, EntryKey, 5);

    #[test]
    pub fn init() {
        env_logger::init();
        let server_group = "sstable_index_init";
        let server_addr = String::from("127.0.0.1:5200");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 16 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], server_group).unwrap(),
        );
        client.new_schema_with_id(super::get_schema()).wait();

        let mut tree: LevelTree<SmallPage> = LevelTree::new(&client);
        let id = Id::unit_id();
        let key = smallvec![1, 2, 3, 4, 5, 6];
        let mut tombstones = BTreeSet::new();
        info!("test insertion");

        let mut key_id = key.clone();
        key_with_id(&mut key_id, &id);

        tree.merge(vec![key_id], &mut tombstones);
        let mut cursor = tree.seek(&key, Ordering::Forward);
        assert_eq!(id_from_key(cursor.current().unwrap()), id);
        assert_eq!(tree.len(), 1);
    }
}
<commit_msg>remove sync conflict<commit_after><|endoftext|>


<commit_before>use super::{Connection, Message, MessageItem, Error};
use std::collections::BTreeMap;

/// Client side properties - get and set properties on a remote application.
pub struct Props<'a> {
    name: String,
    path: String,
    interface: String,
    timeout_ms: i32,
    conn: &'a Connection,
}

impl<'a> Props<'a> {
    pub fn new(conn: &'a Connection, name: &str, path: &str, interface: &str, timeout_ms: i32) -> Props<'a> {
        Props {
            name: name.to_string(),
            path: path.to_string(),
            interface: interface.to_string(),
            timeout_ms: timeout_ms,
            conn: conn,
        }
    }

    pub fn get(&self, propname: &str) -> Result<MessageItem, Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "Get").unwrap();
        m.append_items(&[
            MessageItem::Str(self.interface.clone()),
            MessageItem::Str(propname.to_string())
        ]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        let reply = try!(r.as_result()).get_items();
        if reply.len() == 1 {
            if let &MessageItem::Variant(ref v) = &reply[0] {
                return Ok((**v).clone())
            }
       }
       let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply);
       return Err(Error::new_custom("InvalidReply", &f));
    }

    pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "Set").unwrap();
        m.append_items(&[
            MessageItem::Str(self.interface.clone()),
            MessageItem::Str(propname.to_string()),
            MessageItem::Variant(Box::new(value)),
        ]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        try!(r.as_result());
        Ok(())
    }

    pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "GetAll").unwrap();
        m.append_items(&[MessageItem::Str(self.interface.clone())]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        let reply = try!(r.as_result()).get_items();
        if reply.len() == 1 {
            if let &MessageItem::Array(ref a, _) = &reply[0] {
                let mut t = BTreeMap::new();
                let mut haserr = false;
                for p in a.iter() {
                    if let &MessageItem::DictEntry(ref k, ref v) = p {
                        if let &MessageItem::Str(ref ks) = &**k {
                            if let &MessageItem::Variant(ref vv) = &**v {
                                t.insert(ks.to_string(), (**vv).clone());
                            } else { haserr = true; };
                        } else { haserr = true; };
                    } else { haserr = true; };
                }
                if !haserr { return Ok(t) };
            }
        }
        let f = format!("Invalid reply for property GetAll: '{:?}'", reply);
        return Err(Error::new_custom("InvalidReply", &f));
    }
}

/// Wrapper around Props that keeps a map of fetched properties.
pub struct PropHandler<'a> {
    p: Props<'a>,
    map: BTreeMap<String, MessageItem>,
}

impl<'a> PropHandler<'a> {
    pub fn new(p: Props) -> PropHandler {
        PropHandler { p: p, map: BTreeMap::new() }
    }

    pub fn get_all(&mut self) -> Result<(), Error> {
        self.map = try!(self.p.get_all());
        Ok(())
    }

    pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map }
    pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map }

    pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> {
        let v = try!(self.p.get(propname));
        self.map.insert(propname.to_string(), v);
        Ok(self.map.get(propname).unwrap())
    }

    pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> {
        try!(self.p.set(propname, value.clone()));
        self.map.insert(propname.to_string(), value);
        Ok(())
    }

    fn invalid_args(m: &Message) -> Message {
        Message::new_error(m, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid arguments").unwrap()
    }

    /// Deprecated: use objpath instead
    fn handle_get(&self, msg: &mut Message) -> Message {
        let items = msg.get_items();
        let name = if let Some(s) = items.get(1) { s } else { return PropHandler::invalid_args(msg) };
        let name = if let &MessageItem::Str(ref s) = name { s } else { return PropHandler::invalid_args(msg) };
        let value = if let Some(s) = self.map.get(name) { s } else { return PropHandler::invalid_args(msg) };

        let mut reply = Message::new_method_return(msg).unwrap();
        reply.append_items(&[MessageItem::Variant(Box::new(value.clone()))]);
        reply
    }

    /// Deprecated: Broken. Use objpath instead
    fn handle_getall(&self, msg: &mut Message) -> Message {
        let mut reply = Message::new_method_return(msg).unwrap();
        for (k, v) in self.map.iter() {
            reply.append_items(&[MessageItem::DictEntry(Box::new(MessageItem::Str(k.clone())), Box::new(v.clone()))]);
        }
        reply
    }

    /* Return value:
       None => not handled,
       Some(Err(())) => message reply send failed,
       Some(Ok()) => message reply send ok */
    pub fn handle_message(&mut self, msg: &mut Message) -> Option<Result<(), ()>> {
        let (_, path, iface, method) = msg.headers();
        if iface.is_none() || &*iface.unwrap() != "org.freedesktop.DBus.Properties" { return None; }
        if path.is_none() || path.unwrap() != self.p.path { return None; }
        if method.is_none() { return None; }

        let items = msg.get_items();
        if let Some(i) = items.get(0) {
            if let &MessageItem::Str(ref s) = i {
                if *s != self.p.interface { return None; }
            } else { return None; } // Hmm, invalid message
        } else { return None }; // Hmm, invalid message

        // Ok, we have a match
        let reply = match &*method.unwrap() {
            "Get" => self.handle_get(msg),
//            "Set" => self.handle_set(msg),
            "GetAll" => self.handle_getall(msg),
            _ => PropHandler::invalid_args(msg)
        };
        Some(self.p.conn.send(reply).map(|_| ()))
    }
}

/* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but PolicyKit should be around on most distros. */
#[test]
fn test_get_policykit_version() {
    use super::BusType;
    let c = Connection::get_private(BusType::System).unwrap();
    let p = Props::new(&c, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority",
        "org.freedesktop.PolicyKit1.Authority", 10000);

    /* Let's use both the get and getall methods and see if we get the same result */
    let v = p.get("BackendVersion").unwrap();
    let vall = p.get_all().unwrap();
    let v2 = vall.get("BackendVersion").unwrap();

    assert_eq!(&v, &*v2);
    match v {
        MessageItem::Str(ref s) => { println!("Policykit Backend version is {}", s); }
        _ => { panic!("Invalid Get: {:?}", v); }
    };
}

<commit_msg>prop: Deprecate handle_message too<commit_after>use super::{Connection, Message, MessageItem, Error};
use std::collections::BTreeMap;

/// Client side properties - get and set properties on a remote application.
pub struct Props<'a> {
    name: String,
    path: String,
    interface: String,
    timeout_ms: i32,
    conn: &'a Connection,
}

impl<'a> Props<'a> {
    pub fn new(conn: &'a Connection, name: &str, path: &str, interface: &str, timeout_ms: i32) -> Props<'a> {
        Props {
            name: name.to_string(),
            path: path.to_string(),
            interface: interface.to_string(),
            timeout_ms: timeout_ms,
            conn: conn,
        }
    }

    pub fn get(&self, propname: &str) -> Result<MessageItem, Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "Get").unwrap();
        m.append_items(&[
            MessageItem::Str(self.interface.clone()),
            MessageItem::Str(propname.to_string())
        ]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        let reply = try!(r.as_result()).get_items();
        if reply.len() == 1 {
            if let &MessageItem::Variant(ref v) = &reply[0] {
                return Ok((**v).clone())
            }
       }
       let f = format!("Invalid reply for property get {}: '{:?}'", propname, reply);
       return Err(Error::new_custom("InvalidReply", &f));
    }

    pub fn set(&self, propname: &str, value: MessageItem) -> Result<(), Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "Set").unwrap();
        m.append_items(&[
            MessageItem::Str(self.interface.clone()),
            MessageItem::Str(propname.to_string()),
            MessageItem::Variant(Box::new(value)),
        ]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        try!(r.as_result());
        Ok(())
    }

    pub fn get_all(&self) -> Result<BTreeMap<String, MessageItem>, Error> {
        let mut m = Message::new_method_call(&self.name, &self.path,
            "org.freedesktop.DBus.Properties", "GetAll").unwrap();
        m.append_items(&[MessageItem::Str(self.interface.clone())]);
        let mut r = try!(self.conn.send_with_reply_and_block(m, self.timeout_ms));
        let reply = try!(r.as_result()).get_items();
        if reply.len() == 1 {
            if let &MessageItem::Array(ref a, _) = &reply[0] {
                let mut t = BTreeMap::new();
                let mut haserr = false;
                for p in a.iter() {
                    if let &MessageItem::DictEntry(ref k, ref v) = p {
                        if let &MessageItem::Str(ref ks) = &**k {
                            if let &MessageItem::Variant(ref vv) = &**v {
                                t.insert(ks.to_string(), (**vv).clone());
                            } else { haserr = true; };
                        } else { haserr = true; };
                    } else { haserr = true; };
                }
                if !haserr { return Ok(t) };
            }
        }
        let f = format!("Invalid reply for property GetAll: '{:?}'", reply);
        return Err(Error::new_custom("InvalidReply", &f));
    }
}

/// Wrapper around Props that keeps a map of fetched properties.
pub struct PropHandler<'a> {
    p: Props<'a>,
    map: BTreeMap<String, MessageItem>,
}

impl<'a> PropHandler<'a> {
    pub fn new(p: Props) -> PropHandler {
        PropHandler { p: p, map: BTreeMap::new() }
    }

    pub fn get_all(&mut self) -> Result<(), Error> {
        self.map = try!(self.p.get_all());
        Ok(())
    }

    pub fn map_mut(&mut self) -> &mut BTreeMap<String, MessageItem> { &mut self.map }
    pub fn map(&self) -> &BTreeMap<String, MessageItem> { &self.map }

    pub fn get(&mut self, propname: &str) -> Result<&MessageItem, Error> {
        let v = try!(self.p.get(propname));
        self.map.insert(propname.to_string(), v);
        Ok(self.map.get(propname).unwrap())
    }

    pub fn set(&mut self, propname: &str, value: MessageItem) -> Result<(), Error> {
        try!(self.p.set(propname, value.clone()));
        self.map.insert(propname.to_string(), value);
        Ok(())
    }

    fn invalid_args(m: &Message) -> Message {
        Message::new_error(m, "org.freedesktop.DBus.Error.InvalidArgs", "Invalid arguments").unwrap()
    }

    /// Deprecated: use objpath instead
    fn handle_get(&self, msg: &mut Message) -> Message {
        let items = msg.get_items();
        let name = if let Some(s) = items.get(1) { s } else { return PropHandler::invalid_args(msg) };
        let name = if let &MessageItem::Str(ref s) = name { s } else { return PropHandler::invalid_args(msg) };
        let value = if let Some(s) = self.map.get(name) { s } else { return PropHandler::invalid_args(msg) };

        let mut reply = Message::new_method_return(msg).unwrap();
        reply.append_items(&[MessageItem::Variant(Box::new(value.clone()))]);
        reply
    }

    /// Deprecated: Broken. Use objpath instead
    fn handle_getall(&self, msg: &mut Message) -> Message {
        let mut reply = Message::new_method_return(msg).unwrap();
        for (k, v) in self.map.iter() {
            reply.append_items(&[MessageItem::DictEntry(Box::new(MessageItem::Str(k.clone())), Box::new(v.clone()))]);
        }
        reply
    }

    /// Deprecated: Broken. Use objpath instead
    /// Return value:
    ///   None => not handled,
    ///   Some(Err(())) => message reply send failed,
    ///   Some(Ok()) => message reply send ok
    pub fn handle_message(&mut self, msg: &mut Message) -> Option<Result<(), ()>> {
        let (_, path, iface, method) = msg.headers();
        if iface.is_none() || &*iface.unwrap() != "org.freedesktop.DBus.Properties" { return None; }
        if path.is_none() || path.unwrap() != self.p.path { return None; }
        if method.is_none() { return None; }

        let items = msg.get_items();
        if let Some(i) = items.get(0) {
            if let &MessageItem::Str(ref s) = i {
                if *s != self.p.interface { return None; }
            } else { return None; } // Hmm, invalid message
        } else { return None }; // Hmm, invalid message

        // Ok, we have a match
        let reply = match &*method.unwrap() {
            "Get" => self.handle_get(msg),
//            "Set" => self.handle_set(msg),
            "GetAll" => self.handle_getall(msg),
            _ => PropHandler::invalid_args(msg)
        };
        Some(self.p.conn.send(reply).map(|_| ()))
    }
}

/* Unfortunately org.freedesktop.DBus has no properties we can use for testing, but PolicyKit should be around on most distros. */
#[test]
fn test_get_policykit_version() {
    use super::BusType;
    let c = Connection::get_private(BusType::System).unwrap();
    let p = Props::new(&c, "org.freedesktop.PolicyKit1", "/org/freedesktop/PolicyKit1/Authority",
        "org.freedesktop.PolicyKit1.Authority", 10000);

    /* Let's use both the get and getall methods and see if we get the same result */
    let v = p.get("BackendVersion").unwrap();
    let vall = p.get_all().unwrap();
    let v2 = vall.get("BackendVersion").unwrap();

    assert_eq!(&v, &*v2);
    match v {
        MessageItem::Str(ref s) => { println!("Policykit Backend version is {}", s); }
        _ => { panic!("Invalid Get: {:?}", v); }
    };
}

<|endoftext|>


<commit_before>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::io;
use std::boxed::FnBox;

use mio;

use byteorder::{ BigEndian, WriteBytesExt, ReadBytesExt };

use super::Protocol;
use pipe::*;
use endpoint::*;
use global::*;
use event_loop_msg::SocketEvt;
use EventLoop;
use EventLoopAction;
use Message;

pub struct Resp {
    pipe: Option<Pipe>,
    evt_sender: Rc<Sender<SocketEvt>>,
    cancel_send_timeout: Option<EventLoopAction>,
    cancel_recv_timeout: Option<EventLoopAction>,
    pending_send: Option<Rc<Message>>,
    pending_recv: bool,
    backtrace: Vec<u8>,
    ttl: u8
}

impl Resp {
    pub fn new(evt_sender: Rc<Sender<SocketEvt>>) -> Resp {
        Resp {
            pipe: None,
            evt_sender: evt_sender,
            cancel_send_timeout: None,
            cancel_recv_timeout: None,
            pending_send: None,
            pending_recv: false,
            backtrace: Vec::with_capacity(64),
            ttl: 8
        }
    }

    fn on_msg_send_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_send_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_send = None;
    }

    fn on_msg_send_finished_ok(&mut self, event_loop: &mut EventLoop) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgSent);

        if let Some(pipe) = self.pipe.as_mut() {
            pipe.finish_send();
        }
    }

    fn on_msg_send_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_send_finished(event_loop, SocketEvt::MsgNotSent(err));

        if let Some(pipe) = self.pipe.as_mut() {
            pipe.cancel_send();
        }
    }

    fn on_msg_send_started(&mut self) {
        self.pending_send = None;
    }

    fn process_send_result(&mut self, event_loop: &mut EventLoop, sent: bool, sending: bool) {
        if sent {
            self.on_msg_send_finished_ok(event_loop);
        } else if sending {
            self.on_msg_send_started();
        }
    }

    fn on_msg_recv_finished(&mut self, event_loop: &mut EventLoop, evt: SocketEvt) {
        let _ = self.evt_sender.send(evt);
        let timeout = self.cancel_recv_timeout.take();

        timeout.map(|cancel_timeout| cancel_timeout.call_box((event_loop,)));

        self.pending_recv = false;
    }

    fn on_msg_recv_finished_ok(&mut self, event_loop: &mut EventLoop, msg: Message) {
        self.save_received_header_to_backtrace(&msg);
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgRecv(msg));

        if let Some(pipe) = self.pipe.as_mut() {
            pipe.finish_recv();
        }
    }

    fn on_msg_recv_finished_err(&mut self, event_loop: &mut EventLoop, err: io::Error) {
        self.on_msg_recv_finished(event_loop, SocketEvt::MsgNotRecv(err));

        if let Some(pipe) = self.pipe.as_mut() {
            pipe.cancel_recv();
        }
    }

    fn on_msg_recv_started(&mut self, _: mio::Token) {
        self.pending_recv = false;
    }

    fn process_recv_result(
        &mut self,
        event_loop: &mut EventLoop,
        received: Option<(Message, mio::Token)>,
        receiving: Option<mio::Token>) {

        if let Some((raw_msg, from)) = received {
            self.on_raw_msg_recv_from(event_loop, raw_msg, from);
        }
        else if let Some(token) = receiving {
            self.on_msg_recv_started(token);
        }
    }

    fn on_raw_msg_recv_from(&mut self, event_loop: &mut EventLoop, raw_msg: Message, pipe_token: mio::Token) {
        match self.raw_msg_to_msg(pipe_token, raw_msg) {
            Ok(None)      => {}
            Ok(Some(msg)) => self.on_msg_recv_finished_ok(event_loop, msg),
            Err(e)        => self.on_msg_recv_finished_err(event_loop, e)
        }
    }

    fn save_received_header_to_backtrace(&mut self, msg: &Message) {
        self.backtrace.clear();
        self.backtrace.push_all(msg.get_header());
    }

    fn raw_msg_to_msg(&mut self, pipe_token: mio::Token, raw_msg: Message) -> io::Result<Option<Message>> {
        let (mut header, mut body) = raw_msg.explode();
        let pipe_id = pipe_token.as_usize() as u32;

        header.reserve(4);
        try!(header.write_u32::<BigEndian>(pipe_id));

        let mut hops = 0;
        loop {
            if hops >= self.ttl {
                return Ok(None);
            }

            hops += 1;

            if body.len() < 4 {
                return Ok(None);
            }

            let tail = body.split_off(4);
            header.push_all(&body);

            let position = header.len() - 4;
            if header[position] & 0x80 != 0 {
                let msg = Message::with_header_and_body(header, tail);

                return Ok(Some(msg));
            }
            body = tail;
        }

    }

    fn msg_to_raw_msg(&mut self, msg: Message) -> io::Result<(Message, mio::Token)> {
        let (mut header, body) = msg.explode();
        let pipe_id_bytes = vec!(
            self.backtrace[0],
            self.backtrace[1],
            self.backtrace[2],
            self.backtrace[3]
        );
        let mut pipe_id_reader = io::Cursor::new(pipe_id_bytes);
        let pipe_id = try!(pipe_id_reader.read_u32::<BigEndian>());
        let pipe_token = mio::Token(pipe_id as usize);

        self.restore_saved_backtrace_to_header(&mut header);
        self.backtrace.clear();

        Ok((Message::with_header_and_body(header, body), pipe_token))
    }

    fn restore_saved_backtrace_to_header(&self, header: &mut Vec<u8>) {
        let backtrace = &self.backtrace[4..];

        header.reserve(backtrace.len());
        header.push_all(backtrace);
    }
}

impl Protocol for Resp {
    fn id(&self) -> u16 {
        SocketType::Respondent.id()
    }

    fn peer_id(&self) -> u16 {
        SocketType::Surveyor.id()
    }

    fn add_endpoint(&mut self, token: mio::Token, endpoint: Endpoint) {
        self.pipe = Some(Pipe::new(token, endpoint));
    }

    fn remove_endpoint(&mut self, token: mio::Token) -> Option<Endpoint> {
        if Some(token) == self.pipe.as_ref().map(|p| p.token()) {
            self.pipe.take().map(|p| p.remove())
        } else {
            None
        }
    }

    fn send(&mut self, event_loop: &mut EventLoop, msg: Message, cancel_timeout: EventLoopAction) {
        self.cancel_send_timeout = Some(cancel_timeout);

        if self.pipe.is_none() {
            self.pending_send = Some(Rc::new(msg));
            return;
        }

        let (raw_msg, pipe_token) = match self.msg_to_raw_msg(msg) {
            Err(e) => return self.on_msg_send_finished_err(event_loop, e),
            Ok((raw_msg, pipe_token)) => (raw_msg, pipe_token)
        };

        let mut pipe = self.pipe.take().unwrap();
        let mut sent = false;
        let mut sending = false;
        let msg = Rc::new(raw_msg);

        if pipe_token != pipe.token() {
            let err = io::Error::new(io::ErrorKind::NotConnected, "original surveyor disconnected");

            self.on_msg_send_finished_err(event_loop, err);
            self.pipe = Some(pipe);

            return;
        }

        match pipe.send(msg.clone()) {
            Ok(SendStatus::Completed)  => sent = true,
            Ok(SendStatus::InProgress) => sending = true,
            _ => {}
        }

        self.pipe = Some(pipe);
        self.pending_send = Some(msg);
        self.process_send_result(event_loop, sent, sending);
    }

    fn on_send_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "send timeout reached");

        self.on_msg_send_finished_err(event_loop, err);
    }

    fn recv(&mut self, event_loop: &mut EventLoop, cancel_timeout: EventLoopAction) {
        self.cancel_recv_timeout = Some(cancel_timeout);

        if self.pipe.is_none() {
            self.pending_recv = true;
            return;
        }

        let mut pipe = self.pipe.take().unwrap();
        let mut received = None;
        let mut receiving = None;

        match pipe.recv() {
            Ok(RecvStatus::Completed(msg)) => received = Some((msg, pipe.token())),
            Ok(RecvStatus::InProgress)     => receiving = Some(pipe.token()),
            _ => {}
        }

        self.pipe = Some(pipe);
        self.pending_recv = true;
        self.process_recv_result(event_loop, received, receiving);
    }

    fn on_recv_timeout(&mut self, event_loop: &mut EventLoop) {
        let err = io::Error::new(io::ErrorKind::TimedOut, "recv timeout reached");

        self.on_msg_recv_finished_err(event_loop, err);
    }

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) -> io::Result<()> {
        if self.pipe.is_none() {
            return Ok(());
        }
        if Some(token) != self.pipe.as_ref().map(|p| p.token()) {
            return Ok(());
        }
        let mut sent = false;
        let mut sending = false;
        let mut received = None;
        let mut receiving = None;

        if let Some(pipe) = self.pipe.as_mut() {
            let has_pending_send = self.pending_send.is_some();
            let has_pending_recv = self.pending_recv;
            let (s, r) = try!(pipe.ready(event_loop, events));
            sent = s;
            received = r.map(|msg| (msg, pipe.token()));

            if has_pending_send && !sent && pipe.can_resume_send() {
                let msg = self.pending_send.as_ref().unwrap();

                match try!(pipe.send(msg.clone())) {
                    SendStatus::Completed  => sent = true,
                    SendStatus::InProgress => sending = true,
                    _ => {}
                }
            }

            if has_pending_recv && received.is_none() && pipe.can_resume_recv() {
                match try!(pipe.recv()) {
                    RecvStatus::Completed(msg) => received = Some((msg, pipe.token())),
                    RecvStatus::InProgress     => receiving = Some(token),
                    _ => {}
                }
            }
        }

        self.process_send_result(event_loop, sent, sending);
        self.process_recv_result(event_loop, received, receiving);

        Ok(())
    }
}
<commit_msg>Refactors Resp to use sender and receiver<commit_after>// Copyright 2015 Copyright (c) 2015 Benoît Labaere (benoit.labaere@gmail.com)
//
// Licensed under the MIT license LICENSE or <http://opensource.org/licenses/MIT>
// This file may not be copied, modified, or distributed except according to those terms.

use std::rc::Rc;
use std::sync::mpsc::Sender;
use std::io;

use mio;

use byteorder::{ BigEndian, WriteBytesExt, ReadBytesExt };

use super::Protocol;
use pipe::*;
use endpoint::*;
use global::*;
use event_loop_msg::SocketEvt;
use EventLoop;
use EventLoopAction;
use Message;

use super::sender::*;
use super::receiver::*;

pub struct Resp {
    pipe: Option<Pipe>,
    msg_sender: UnaryMsgSender,
    msg_receiver: UnaryMsgReceiver,
    codec: Codec
}

impl Resp {
    pub fn new(evt_tx: Rc<Sender<SocketEvt>>) -> Resp {
        Resp {
            pipe: None,
            msg_sender: UnaryMsgSender::new(evt_tx.clone()),
            msg_receiver: UnaryMsgReceiver::new(evt_tx.clone()),
            codec: Codec::new()
        }
    }
}

impl Protocol for Resp {
    fn id(&self) -> u16 {
        SocketType::Respondent.id()
    }

    fn peer_id(&self) -> u16 {
        SocketType::Surveyor.id()
    }

    fn add_endpoint(&mut self, token: mio::Token, endpoint: Endpoint) {
        self.pipe = Some(Pipe::new(token, endpoint));
    }

    fn remove_endpoint(&mut self, token: mio::Token) -> Option<Endpoint> {
        if Some(token) == self.pipe.as_ref().map(|p| p.token()) {
            self.pipe.take().map(|p| p.remove())
        } else {
            None
        }
    }

    fn send(&mut self, event_loop: &mut EventLoop, msg: Message, cancel_timeout: EventLoopAction) {
        match self.codec.encode(msg) {
            Err(e) => self.msg_sender.on_send_err(event_loop, e, self.pipe.as_mut()),
            Ok((raw_msg, _)) => self.msg_sender.send(event_loop, raw_msg, cancel_timeout, self.pipe.as_mut())
        }
    }

    fn on_send_timeout(&mut self, event_loop: &mut EventLoop) {
        self.msg_sender.on_send_timeout(event_loop, self.pipe.as_mut())
    }

    fn recv(&mut self, event_loop: &mut EventLoop, cancel_timeout: EventLoopAction) {
        self.msg_receiver.recv(event_loop, &mut self.codec, cancel_timeout, self.pipe.as_mut())
    }

    fn on_recv_timeout(&mut self, event_loop: &mut EventLoop) {
        self.msg_receiver.on_recv_timeout(event_loop, self.pipe.as_mut())
    }

    fn ready(&mut self, event_loop: &mut EventLoop, token: mio::Token, events: mio::EventSet) -> io::Result<()> {
        let mut sent = false;
        let mut received = None;

        if let Some(pipe) = self.pipe.as_mut() {
            let (s, r) = try!(pipe.ready(event_loop, events));
            sent = s;
            received = r;
        }

        let send_result = match sent {
            true  => Ok(self.msg_sender.sent_by(event_loop, token, self.pipe.as_mut())),
            false => self.msg_sender.resume_send(event_loop, token, self.pipe.as_mut())
        };

        let recv_result = match received {
            Some(msg) => Ok(self.msg_receiver.received_by(event_loop, &mut self.codec, msg, token, self.pipe.as_mut())),
            None => self.msg_receiver.resume_recv(event_loop, &mut self.codec, token, self.pipe.as_mut())
        };

        send_result.and(recv_result)
    }
}

struct Codec {
    backtrace: Vec<u8>,
    ttl: u8
}

impl Codec {
    fn new() -> Codec {
        Codec {
            backtrace: Vec::with_capacity(64),
            ttl: 8
        }
    }

    fn encode(&mut self, msg: Message) -> io::Result<(Message, mio::Token)> {
        let (mut header, body) = msg.explode();
        let pipe_id_bytes = vec!(
            self.backtrace[0],
            self.backtrace[1],
            self.backtrace[2],
            self.backtrace[3]
        );
        let mut pipe_id_reader = io::Cursor::new(pipe_id_bytes);
        let pipe_id = try!(pipe_id_reader.read_u32::<BigEndian>());
        let pipe_token = mio::Token(pipe_id as usize);

        self.restore_saved_backtrace_to_header(&mut header);
        self.backtrace.clear();

        Ok((Message::with_header_and_body(header, body), pipe_token))
    }

    fn restore_saved_backtrace_to_header(&self, header: &mut Vec<u8>) {
        let backtrace = &self.backtrace[4..];

        header.reserve(backtrace.len());
        header.push_all(backtrace);
    }

    fn save_received_header_to_backtrace(&mut self, msg: &Message) {
        self.backtrace.clear();
        self.backtrace.push_all(msg.get_header());
    }
}

impl MsgDecoder for Codec {
    fn decode(&mut self, raw_msg: Message, pipe_token: mio::Token) -> io::Result<Option<Message>> {
        let (mut header, mut body) = raw_msg.explode();
        let pipe_id = pipe_token.as_usize() as u32;

        header.reserve(4);
        try!(header.write_u32::<BigEndian>(pipe_id));

        let mut hops = 0;
        loop {
            if hops >= self.ttl {
                return Ok(None);
            }

            hops += 1;

            if body.len() < 4 {
                return Ok(None);
            }

            let tail = body.split_off(4);
            header.push_all(&body);

            let position = header.len() - 4;
            if header[position] & 0x80 != 0 {
                let msg = Message::with_header_and_body(header, tail);

                self.save_received_header_to_backtrace(&msg);

                return Ok(Some(msg));
            }
            body = tail;
        }
    }
}<|endoftext|>