<commit_before>//! Lambda encoding for byte strings

use lambda_calculus::term::*;
use lambda_calculus::booleans::{tru, fls};
use std::char;

/// Decode lambda-encoded data as a `String`.
///
/// # Example
/// ```
/// use blc::binary_encoding::from_binary;
/// use blc::lambda_encoding::decode;
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(decode(k.unwrap()), "(λλ2)");
/// ```
pub fn decode(term: Term) -> String {
    if term == fls() {
        "".into()
    } else if term.is_list() && term.head_ref().unwrap().is_list() {
        let (head, tail) = term.uncons().unwrap(); // safe, ensured by is_list
        let byte = decode_byte(head);
        let chr = char::from(byte);
        chr.to_string() + &decode(tail)
    } else if term.head_ref() == Ok(&fls()) {
        "1".to_string() + &decode(term.tail().unwrap())
    } else if term.head_ref() == Ok(&tru()) {
        "0".to_string() + &decode(term.tail().unwrap())
    } else {
        format!("({})", term)
    }
}

fn decode_byte(encoded_byte: Term) -> u8 {
    let bits = encoded_byte
        .into_iter()
        .map(|t| (t
            .unabs()
            .and_then(|t| t.unabs())
            .and_then(|t| t.unvar())
            .expect("not a lambda-encoded byte!") - 1) as u8
        );

    !bits.fold(0, |acc, b| acc * 2 + b)
}

fn encode_byte(byte: u8) -> Term {
    let bitstr = format!("{:08b}", byte);
    let bits = bitstr.as_bytes();
    Term::from(bits.into_iter().map(|&bit| encode_bit(bit)).collect::<Vec<Term>>())
}

fn encode_bit(bit: u8) -> Term {
    match bit {
        b'0' => tru(),
        b'1' => fls(),
        _ => unreachable!()
    }
}

/// Encode bytes as a lambda `Term`.
///
/// # Example
/// ```
/// use blc::lambda_encoding::encode;
///
/// assert_eq!(&*format!("{}", encode(b"a")),
///     "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
/// ```
pub fn encode(input: &[u8]) -> Term {
    Term::from(input.into_iter().map(|&b| encode_byte(b)).collect::<Vec<Term>>())
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::from_binary;
    use std::str;

    #[test]
    fn encoding_lambda() {
        assert_eq!(&*format!("{}", encode(b"0")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"1")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"a")),
            "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
    }

    #[test]
    fn decoding() {
        let k =     from_binary(b"0000110").unwrap();
        let s =     from_binary(b"00000001011110100111010").unwrap();
        let quine = from_binary(b"000101100100011010000000000001011\
                                  011110010111100111111011111011010").unwrap();

        assert_eq!(decode(k),     "(λλ2)");
        assert_eq!(decode(s),     "(λλλ31(21))");
        assert_eq!(decode(quine), "(λ1((λ11)(λλλλλ14(3(55)2)))1)");
    }

    #[test]
    fn decode_encode_lambda() {
        assert_eq!(decode(encode(b"herp derp")),             "herp derp");
        assert_eq!(decode(encode(b"0111010101011")),         "0111010101011");
        assert_eq!(decode(encode(b"01zeros110and1ones101")), "01zeros110and1ones101");
        assert_eq!(decode(encode(b"\0(1)")),                 "\0(1)");
    }
}
<commit_msg>minor adjustments to tests and comments<commit_after>//! Lambda encoding for byte strings

use lambda_calculus::term::*;
use lambda_calculus::booleans::{tru, fls};
use std::char;

/// Decode lambda-encoded data as a `String`.
///
/// # Example
/// ```
/// use blc::binary_encoding::from_binary;
/// use blc::lambda_encoding::decode;
///
/// let k = from_binary(b"0000110");
///
/// assert!(k.is_ok());
/// assert_eq!(decode(k.unwrap()), "(λλ2)");
/// ```
pub fn decode(term: Term) -> String {
    if term == fls() {
        "".into()
    } else if term.is_list() && term.head_ref().unwrap().is_list() { // safe
        let (head, tail) = term.uncons().unwrap(); // safe
        let byte = decode_byte(head);
        let chr = char::from(byte);
        chr.to_string() + &decode(tail)
    } else if term.head_ref() == Ok(&fls()) {
        "1".to_string() + &decode(term.tail().unwrap()) // safe
    } else if term.head_ref() == Ok(&tru()) {
        "0".to_string() + &decode(term.tail().unwrap()) // safe
    } else {
        format!("({})", term)
    }
}

// TODO: make safer
fn decode_byte(encoded_byte: Term) -> u8 {
    let bits = encoded_byte
        .into_iter()
        .map(|t| (t
            .unabs()
            .and_then(|t| t.unabs())
            .and_then(|t| t.unvar())
            .expect("not a lambda-encoded byte!") - 1) as u8
        );

    !bits.fold(0, |acc, b| acc * 2 + b)
}

fn encode_byte(byte: u8) -> Term {
    let bitstr = format!("{:08b}", byte);
    let bits = bitstr.as_bytes();
    Term::from(bits.into_iter().map(|&bit| encode_bit(bit)).collect::<Vec<Term>>())
}

fn encode_bit(bit: u8) -> Term {
    match bit {
        b'0' => tru(),
        b'1' => fls(),
        _ => unreachable!()
    }
}

/// Encode bytes as a lambda `Term`.
///
/// # Example
/// ```
/// use blc::lambda_encoding::encode;
///
/// assert_eq!(&*format!("{}", encode(b"a")),
///     "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
/// ```
pub fn encode(input: &[u8]) -> Term {
    Term::from(input.into_iter().map(|&b| encode_byte(b)).collect::<Vec<Term>>())
}

#[cfg(test)]
mod test {
    use super::*;
    use binary_encoding::from_binary;
    use std::str;

    #[test]
    fn encoding_lambda() {
        assert_eq!(&*format!("{}", encode(b"0")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"1")),
            "λ1(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
        assert_eq!(&*format!("{}", encode(b"a")),
            "λ1(λ1(λλ2)(λ1(λλ1)(λ1(λλ1)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ2)(λ1(λλ1)(λλ1)))))))))(λλ1)");
    }

    #[test]
    fn decoding_lambda() {
        let k =     from_binary(b"0000110").unwrap();
        let s =     from_binary(b"00000001011110100111010").unwrap();
        let quine = from_binary(b"000101100100011010000000000001011\
                                  011110010111100111111011111011010").unwrap();

        assert_eq!(decode(k),     "(λλ2)");
        assert_eq!(decode(s),     "(λλλ31(21))");
        assert_eq!(decode(quine), "(λ1((λ11)(λλλλλ14(3(55)2)))1)");
    }

    #[test]
    fn decode_encode_lambda() {
        assert_eq!(decode(encode(b"herp derp")),             "herp derp");
        assert_eq!(decode(encode(b"0111010101011")),         "0111010101011");
        assert_eq!(decode(encode(b"01zeros110and1ones101")), "01zeros110and1ones101");
        assert_eq!(decode(encode(b"\0(1)")),                 "\0(1)");
    }
}
<|endoftext|>


<commit_before>use std::mem;
use std::ptr;

use std::marker::Copy;
use std::clone::Clone;

use std::ops::Deref;
use std::ops::DerefMut;

use std::sync::{RwLock, RwLockWriteGuard};
use std::sync::atomic::{AtomicUsize, Ordering};

use std::fmt::{Debug, Formatter, Result};

use super::super::round_up_to_next_highest_power_of_two;

struct Bucket {
    key: Option<i32>,
    value: Option<i32>,
    next: Option<Link>
}

impl Bucket {

    fn empty() -> Bucket {
        Bucket {
            key: None,
            value: None,
            next: None
        }
    }

    fn new(key: i32, value: i32) -> Bucket {
        Bucket {
            key: Some(key),
            value: Some(value),
            next: None
        }
    }
}

impl Debug for Bucket {

    fn fmt(&self, fmt: &mut Formatter) -> Result {
        write!(fmt, "[ Key = {:?} Value = {:?} ]", self.key, self.value)
    }
}

struct Link {

    ptr: *mut Bucket
}

impl Link {

    fn new(bucket: Bucket) -> Link {
        Link {
            ptr: Box::into_raw(Box::new(bucket))
        }
    }
}

impl Deref for Link {
    type Target = Bucket;

    fn deref(&self) -> &Bucket {
        unsafe { mem::transmute(self.ptr) }
    }
}

impl DerefMut for Link {

    fn deref_mut(&mut self) -> &mut Bucket {
        unsafe { mem::transmute(self.ptr) }
    }
}

impl Clone for Link{

    fn clone(&self) -> Link {
        Link { ptr: self.ptr }
    }
}

impl Copy for Link { }
unsafe impl Send for Link { }

pub struct ConcurrentHashMap {
    table: Vec<RwLock<Link>>,
    size: AtomicUsize
}

impl ConcurrentHashMap {

    pub fn new() -> ConcurrentHashMap {
        ConcurrentHashMap::with_capacity(16)
    }

    pub fn with_capacity(capacity: usize) -> ConcurrentHashMap {
        let capacity = round_up_to_next_highest_power_of_two(capacity);
        let mut table = Vec::with_capacity(capacity);
        for _ in 0..capacity {
            table.push(RwLock::new(Link::new(Bucket::empty())));
        }
        ConcurrentHashMap {
            table: table,
            size: AtomicUsize::new(0)
        }
    }

    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    pub fn len(&self) -> usize {
        self.size.load(Ordering::Relaxed)
    }

    pub fn capacity(&self) -> usize {
        self.table.capacity()
    }

    pub fn insert(&mut self, key: i32, val: i32) {
        let index = self.capacity() & key as usize;
        let mut guard = self.table[index].write().unwrap();
        if put(key, val, &mut guard) {
            self.size.fetch_add(1, Ordering::Relaxed);
        }
    }

    pub fn remove(&mut self, key: i32) -> Option<i32> {
        let index = self.capacity() & key as usize;
        let mut guard = self.table[index].write().unwrap();
        let result = take(key, &mut guard);
        println!("{:?}", result);
        if result.is_some() {
            self.size.fetch_sub(1, Ordering::Relaxed);
        }
        result
    }
}

fn put(key: i32, val: i32, guard: &mut RwLockWriteGuard<Link>) -> bool {
    let contains = contains(key, guard);
    if contains {
        let mut link = **guard;
        loop {
            if (*link).key == Some(key) {
                link.value = Some(val);
                break;
            }
            match (*link).next {
                Some(next) => link = next,
                None => break,
            }
        }
    }
    else {
        let mut new_bucket = Link::new(Bucket::new(key, val));
        let link = **guard;
        new_bucket.next = Some(link);
        **guard = new_bucket;
    }
    !contains
}

fn contains(key: i32, guard: &RwLockWriteGuard<Link>) -> bool {
    let mut link = **guard;
    loop {
        if (*link).key == Some(key) {
            return true;
        }
        match (*link).next {
            Some(next) => link = next,
            None => return false,
        }
    }
}

fn take(key: i32, guard: &mut RwLockWriteGuard<Link>) -> Option<i32> {
    let mut link = **guard;
    if !link.ptr.is_null() {
        loop {
            if (*link).key == Some(key) {
                match (*link).next {
                    Some(next) => link.next = next.next,
                    None => link.ptr = ptr::null_mut(),
                }
                return (*link).value;
            }
            match (*link).next {
                Some(next) => link = next,
                None => break,
            }
        }
    }
    None
}
<commit_msg>add doc to hash map<commit_after>use std::mem;
use std::ptr;

use std::marker::Copy;
use std::clone::Clone;

use std::ops::Deref;
use std::ops::DerefMut;

use std::sync::{RwLock, RwLockWriteGuard};
use std::sync::atomic::{AtomicUsize, Ordering};

use std::fmt::{Debug, Formatter, Result};

use super::super::round_up_to_next_highest_power_of_two;

struct Bucket {
    key: Option<i32>,
    value: Option<i32>,
    next: Option<Link>
}

impl Bucket {

    fn empty() -> Bucket {
        Bucket {
            key: None,
            value: None,
            next: None
        }
    }

    fn new(key: i32, value: i32) -> Bucket {
        Bucket {
            key: Some(key),
            value: Some(value),
            next: None
        }
    }
}

impl Debug for Bucket {

    fn fmt(&self, fmt: &mut Formatter) -> Result {
        write!(fmt, "[ Key = {:?} Value = {:?} ]", self.key, self.value)
    }
}

struct Link {

    ptr: *mut Bucket
}

impl Link {

    fn new(bucket: Bucket) -> Link {
        Link {
            ptr: Box::into_raw(Box::new(bucket))
        }
    }
}

impl Deref for Link {
    type Target = Bucket;

    fn deref(&self) -> &Bucket {
        unsafe { mem::transmute(self.ptr) }
    }
}

impl DerefMut for Link {

    fn deref_mut(&mut self) -> &mut Bucket {
        unsafe { mem::transmute(self.ptr) }
    }
}

impl Clone for Link{

    fn clone(&self) -> Link {
        Link { ptr: self.ptr }
    }
}

impl Copy for Link { }
unsafe impl Send for Link { }

/// A hash table supporting concurrency for insertions and deletions
///
/// Currnet implementation is non resizeble vector of Read-Write locks-buckets
/// which resolve hash collisions with link to the next key value pair
pub struct ConcurrentHashMap {
    table: Vec<RwLock<Link>>,
    size: AtomicUsize
}

impl ConcurrentHashMap {

    /// Create hash table with vector of locks-buckets with default size which is 16
    pub fn new() -> ConcurrentHashMap {
        ConcurrentHashMap::with_capacity(16)
    }

    /// Create hash table with vector of locks-buckets with specified capacity which will be
    /// increase if needed to next highest power of two
    pub fn with_capacity(capacity: usize) -> ConcurrentHashMap {
        let capacity = round_up_to_next_highest_power_of_two(capacity);
        let mut table = Vec::with_capacity(capacity);
        for _ in 0..capacity {
            table.push(RwLock::new(Link::new(Bucket::empty())));
        }
        ConcurrentHashMap {
            table: table,
            size: AtomicUsize::new(0)
        }
    }

    /// Check if table is empty
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Return size of table
    pub fn len(&self) -> usize {
        self.size.load(Ordering::Relaxed)
    }

    /// Return capacity of locks-buckets vector
    pub fn capacity(&self) -> usize {
        self.table.capacity()
    }

    /// Insert key value pair into table
    /// or update value if specified key is already in table
    pub fn insert(&mut self, key: i32, val: i32) {
        let index = self.capacity() & key as usize;
        let mut guard = self.table[index].write().unwrap();
        if put(key, val, &mut guard) {
            self.size.fetch_add(1, Ordering::Relaxed);
        }
    }

    /// Remove specified key from table return value
    /// or None if key wasn't in the table
    pub fn remove(&mut self, key: i32) -> Option<i32> {
        let index = self.capacity() & key as usize;
        let mut guard = self.table[index].write().unwrap();
        let result = take(key, &mut guard);
        println!("{:?}", result);
        if result.is_some() {
            self.size.fetch_sub(1, Ordering::Relaxed);
        }
        result
    }
}

fn put(key: i32, val: i32, guard: &mut RwLockWriteGuard<Link>) -> bool {
    let contains = contains(key, guard);
    if contains {
        let mut link = **guard;
        loop {
            if (*link).key == Some(key) {
                link.value = Some(val);
                break;
            }
            match (*link).next {
                Some(next) => link = next,
                None => break,
            }
        }
    }
    else {
        let mut new_bucket = Link::new(Bucket::new(key, val));
        let link = **guard;
        new_bucket.next = Some(link);
        **guard = new_bucket;
    }
    !contains
}

fn contains(key: i32, guard: &RwLockWriteGuard<Link>) -> bool {
    let mut link = **guard;
    loop {
        if (*link).key == Some(key) {
            return true;
        }
        match (*link).next {
            Some(next) => link = next,
            None => return false,
        }
    }
}

fn take(key: i32, guard: &mut RwLockWriteGuard<Link>) -> Option<i32> {
    let mut link = **guard;
    if !link.ptr.is_null() {
        loop {
            if (*link).key == Some(key) {
                match (*link).next {
                    Some(next) => link.next = next.next,
                    None => link.ptr = ptr::null_mut(),
                }
                return (*link).value;
            }
            match (*link).next {
                Some(next) => link = next,
                None => break,
            }
        }
    }
    None
}
<|endoftext|>


<commit_before>use super::node::NodeData;
use super::*;
use std::fmt::Debug;

// Assuming the tree is almost full, worst scenario it is half full
// Pick the mid point in each of the levels, this will give us an approximate half key of the tree
pub fn last_node_prev_digest<KS, PS>(
    node_ref: &NodeCellRef,
) -> Option<(usize, NodeCellRef, EntryKey)>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // Use read unchecked for there should be no writer for disk trees
    match &*read_unchecked::<KS, PS>(node_ref) {
        &NodeData::External(ref n) => {
            let keys = n.keys.as_slice_immute();
            Some((n.len, n.prev.clone(), keys[n.len / 2].clone()))
        }
        &NodeData::Internal(ref n) => {
            debug!("Collecting pivot in internal {:?}", node_ref);
            last_node_prev_digest::<KS, PS>(&n.ptrs.as_slice_immute()[..n.len].last().unwrap())
        }
        &NodeData::Empty(ref n) => {
            debug!("Collecting pivot in empty {:?}", node_ref);
            last_node_prev_digest::<KS, PS>(n.left.as_ref().unwrap())
        }
        &NodeData::None => None,
    }
}

// Retain the keys in the left hand side of the mid key
// Best case scenario we can cut the tree in half
// Worst scenario, the will be some node have no key but one ptr
//  In this scenario, we can split its left hand side node and rebalance the keys
//  This can potentially produce a quarter filled page, which makes it still valid as a node
pub fn retain<KS, PS>(tree: &BPlusTree<KS, PS>, mid_key: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    retain_by_node::<KS, PS>(tree, &tree.get_root(), mid_key, 0);
}

fn retain_by_node<KS, PS>(
    tree: &BPlusTree<KS, PS>,
    node_ref: &NodeCellRef,
    mid_key: &EntryKey,
    level: usize,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // Assert the thread have exclusive access to the node
    match &*read_unchecked::<KS, PS>(node_ref) {
        &NodeData::External(_) => {
            // Assert the key exists in the node for it is immutable
            debug!(
                "Retaining keys at {:?}, from node {:?}, external level {}",
                mid_key, node_ref, level
            );
            let mut node = write_node::<KS, PS>(node_ref);
            debug!("Retain key lock obtained for {:?}", node_ref);
            let n = node.extnode_mut(tree);
            let key_index = n.search(mid_key);
            if key_index >= n.len {
                // Pivot is beyond reach, nothing to do
                return;
            }
            let selected_key = &n.keys.as_slice_immute()[key_index];
            let origin_node_len = n.len;
            debug_assert!(
                selected_key >= mid_key,
                "Selected {:?}, mid {:?}",
                selected_key,
                mid_key
            );
            n.len = key_index; // All others will be ignored
            debug_assert_ne!(
                n.len, 0,
                "No keys left in page, selected {:?}, mid {:?}, left ref {:?}",
                selected_key, mid_key, &n.prev
            ); // Assert no empty node after cut
               // Cut out the right half of the node in this tree
            let mut right_node_ref = mem::take(&mut n.next);
            let mut num_removed_keys = origin_node_len - key_index;
            drop(node);
            while !right_node_ref.is_default() {
                debug!("Obtaining right node lock for {:?}", right_node_ref);
                let mut node = write_node::<KS, PS>(&right_node_ref);
                debug!("Right node lock obrained for {:?}", right_node_ref);
                let node_id = node.ext_id();
                right_node_ref = mem::take(node.right_ref_mut().unwrap());
                num_removed_keys += node.len();
                *node = NodeData::Empty(box Default::default());
                make_deleted::<KS, PS>(&node_id);
            }
            tree.len.fetch_sub(num_removed_keys, Release);
            info!("LSM tree retention removed {} keys", num_removed_keys);
        }
        &NodeData::Internal(ref n) => {
            let index = n.search(mid_key);
            retain_by_node::<KS, PS>(tree, &n.ptrs.as_slice_immute()[index], mid_key, level + 1);
            if index >= n.len {
                return;
            }
            assert_ne!(index, 0, "This case is not possible and not handled");
            debug!("Retaining keys at internal level {}", level);
            let mut node = write_node::<KS, PS>(node_ref);
            debug_assert_eq!(
                // Ensure two searches have the same result
                index,
                node.keys()
                    .binary_search(mid_key)
                    .map(|i| i + 1)
                    .unwrap_or_else(|i| i)
            );
            debug_assert_ne!(index, 0);
            let innode = node.innode_mut();
            for ptr in innode.ptrs.as_slice()[index + 1..=innode.len].iter_mut() {
                *ptr = Default::default();
            }
            innode.len = index;
            let mut right_node_ref = mem::take(&mut innode.right);
            drop(node);
            while !right_node_ref.is_default() {
                let mut node = write_node::<KS, PS>(&right_node_ref);
                right_node_ref = mem::take(node.right_ref_mut().unwrap());
                *node = NodeData::Empty(box Default::default());
            }
        }
        &NodeData::Empty(ref n) => {
            retain_by_node::<KS, PS>(tree, &n.right, mid_key, level);
        }
        &NodeData::None => unreachable!(),
    }
}
<commit_msg>set log level<commit_after>use super::node::NodeData;
use super::*;
use std::fmt::Debug;

// Assuming the tree is almost full, worst scenario it is half full
// Pick the mid point in each of the levels, this will give us an approximate half key of the tree
pub fn last_node_prev_digest<KS, PS>(
    node_ref: &NodeCellRef,
) -> Option<(usize, NodeCellRef, EntryKey)>
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // Use read unchecked for there should be no writer for disk trees
    match &*read_unchecked::<KS, PS>(node_ref) {
        &NodeData::External(ref n) => {
            let keys = n.keys.as_slice_immute();
            Some((n.len, n.prev.clone(), keys[n.len / 2].clone()))
        }
        &NodeData::Internal(ref n) => {
            debug!("Collecting pivot in internal {:?}", node_ref);
            last_node_prev_digest::<KS, PS>(&n.ptrs.as_slice_immute()[..n.len].last().unwrap())
        }
        &NodeData::Empty(ref n) => {
            debug!("Collecting pivot in empty {:?}", node_ref);
            last_node_prev_digest::<KS, PS>(n.left.as_ref().unwrap())
        }
        &NodeData::None => None,
    }
}

// Retain the keys in the left hand side of the mid key
// Best case scenario we can cut the tree in half
// Worst scenario, the will be some node have no key but one ptr
//  In this scenario, we can split its left hand side node and rebalance the keys
//  This can potentially produce a quarter filled page, which makes it still valid as a node
pub fn retain<KS, PS>(tree: &BPlusTree<KS, PS>, mid_key: &EntryKey)
where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    retain_by_node::<KS, PS>(tree, &tree.get_root(), mid_key, 0);
}

fn retain_by_node<KS, PS>(
    tree: &BPlusTree<KS, PS>,
    node_ref: &NodeCellRef,
    mid_key: &EntryKey,
    level: usize,
) where
    KS: Slice<EntryKey> + Debug + 'static,
    PS: Slice<NodeCellRef> + 'static,
{
    // Assert the thread have exclusive access to the node
    match &*read_unchecked::<KS, PS>(node_ref) {
        &NodeData::External(_) => {
            // Assert the key exists in the node for it is immutable
            debug!(
                "Retaining keys at {:?}, from node {:?}, external level {}",
                mid_key, node_ref, level
            );
            let mut node = write_node::<KS, PS>(node_ref);
            debug!("Retain key lock obtained for {:?}", node_ref);
            let n = node.extnode_mut(tree);
            let key_index = n.search(mid_key);
            if key_index >= n.len {
                // Pivot is beyond reach, nothing to do
                return;
            }
            let selected_key = &n.keys.as_slice_immute()[key_index];
            let origin_node_len = n.len;
            debug_assert!(
                selected_key >= mid_key,
                "Selected {:?}, mid {:?}",
                selected_key,
                mid_key
            );
            n.len = key_index; // All others will be ignored
            debug_assert_ne!(
                n.len, 0,
                "No keys left in page, selected {:?}, mid {:?}, left ref {:?}",
                selected_key, mid_key, &n.prev
            ); // Assert no empty node after cut
               // Cut out the right half of the node in this tree
            let mut right_node_ref = mem::take(&mut n.next);
            let mut num_removed_keys = origin_node_len - key_index;
            drop(node);
            while !right_node_ref.is_default() {
                trace!("Obtaining right node lock for {:?}", right_node_ref);
                let mut node = write_node::<KS, PS>(&right_node_ref);
                trace!("Right node lock obrained for {:?}", right_node_ref);
                let node_id = node.ext_id();
                right_node_ref = mem::take(node.right_ref_mut().unwrap());
                num_removed_keys += node.len();
                *node = NodeData::Empty(box Default::default());
                make_deleted::<KS, PS>(&node_id);
            }
            tree.len.fetch_sub(num_removed_keys, Release);
            info!("LSM tree retention removed {} keys", num_removed_keys);
        }
        &NodeData::Internal(ref n) => {
            let index = n.search(mid_key);
            retain_by_node::<KS, PS>(tree, &n.ptrs.as_slice_immute()[index], mid_key, level + 1);
            if index >= n.len {
                return;
            }
            assert_ne!(index, 0, "This case is not possible and not handled");
            debug!("Retaining keys at internal level {}", level);
            let mut node = write_node::<KS, PS>(node_ref);
            debug_assert_eq!(
                // Ensure two searches have the same result
                index,
                node.keys()
                    .binary_search(mid_key)
                    .map(|i| i + 1)
                    .unwrap_or_else(|i| i)
            );
            debug_assert_ne!(index, 0);
            let innode = node.innode_mut();
            for ptr in innode.ptrs.as_slice()[index + 1..=innode.len].iter_mut() {
                *ptr = Default::default();
            }
            innode.len = index;
            let mut right_node_ref = mem::take(&mut innode.right);
            drop(node);
            while !right_node_ref.is_default() {
                let mut node = write_node::<KS, PS>(&right_node_ref);
                right_node_ref = mem::take(node.right_ref_mut().unwrap());
                *node = NodeData::Empty(box Default::default());
            }
        }
        &NodeData::Empty(ref n) => {
            retain_by_node::<KS, PS>(tree, &n.right, mid_key, level);
        }
        &NodeData::None => unreachable!(),
    }
}
<|endoftext|>


<commit_before>use std::iter;
use std::fmt;
use std::cmp::Ordering;

pub struct Node<K, V> {
    key: K,
    val: V,
    left:  Option<Box<Node<K, V>>>,
    right: Option<Box<Node<K, V>>>
}

impl<K, V> Node<K, V> {
    pub fn new(key: K, val: V) -> Node<K, V> {
        Node {
            key: key,
            val: val,
            left: None,
            right: None
        }
    }
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter) {
        if depth == 0 {
            writeln!(f, "{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}+--{:?}[{:?}]", iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f);
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f);
        }
    }
}

fn put<K: Ord, V>(x: Option<Box<Node<K,V>>>, key: K, val: V) -> Option<Box<Node<K,V>>> {
    let mut x = x;
    if x.is_none() {
        return Some(Box::new(Node::new(key, val)));
    }
    let cmp = key.cmp(&x.as_ref().unwrap().key);
    match cmp {
        Ordering::Less => {
            let left = x.as_mut().unwrap().left.take();
            x.as_mut().unwrap().left = put(left, key, val)
        },
        Ordering::Greater => {
            let right = x.as_mut().unwrap().right.take();
            x.as_mut().unwrap().right = put(right, key, val)
        },
        Ordering::Equal => {
            x.as_mut().unwrap().val = val
        }
    }
    x
}

pub struct BST<K, V> {
    root: Option<Box<Node<K, V>>>
}

impl<K: Ord, V> BST<K, V> {
    pub fn new() -> BST<K, V> {
        BST { root: None }
    }

    pub fn get(&self, key: K) -> Option<&V> {
        let mut x = self.root.as_ref();
        while x.is_some() {
            match key.cmp(&x.unwrap().key) {
                Ordering::Less => {
                    x = x.unwrap().left.as_ref();
                },
                Ordering::Greater => {
                    x = x.unwrap().right.as_ref();
                },
                Ordering::Equal  => {
                    return Some(&x.unwrap().val)
                }
            }
        }
        None
    }

    pub fn put(&mut self, key: K, val: V) {
        let root = self.root.take();
        self.root = put(root, key, val);
        // if self.root.is_none() {
        //     self.root = Some(Box::new(Node::new(key, val)))
        // } else {

        // }
    }
//     fn delete(&mut self, key: &key);
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for BST<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f);
            Ok(())
        }
    }
}

#[test]
fn test_binary_search_tree() {
    let mut t = BST::<char, usize>::new();
    for (i, c) in "SEARCHEXAMP".chars().enumerate() {
        t.put(c, i);
    }

    //println!("{:?}", t);
    assert_eq!(t.get('E'),  Some(&6));
}
<commit_msg>symbol_tables/binary_search_tree: impl ST for BST<commit_after>use std::iter;
use std::fmt;
use std::cmp::Ordering;
use super::{ST, OrderedST};

pub struct Node<K, V> {
    key: K,
    val: V,
    left:  Option<Box<Node<K, V>>>,
    right: Option<Box<Node<K, V>>>
}

impl<K, V> Node<K, V> {
    pub fn new(key: K, val: V) -> Node<K, V> {
        Node {
            key: key,
            val: val,
            left: None,
            right: None
        }
    }
}

impl<K: fmt::Debug, V: fmt::Debug> Node<K, V> {
    fn dump(&self, depth: usize, f: &mut fmt::Formatter) {
        if depth == 0 {
            writeln!(f, "{:?}[{:?}]", self.key, self.val).unwrap();
        } else {
            writeln!(f, "{}+--{:?}[{:?}]", iter::repeat("|  ").take(depth-1).collect::<Vec<&str>>().concat(),
                     self.key, self.val).unwrap();
        }
        if self.left.is_some() {
            self.left.as_ref().unwrap().dump(depth + 1, f);
        }
        if self.right.is_some() {
            self.right.as_ref().unwrap().dump(depth + 1, f);
        }
    }
}

fn put<K: Ord, V>(x: Option<Box<Node<K,V>>>, key: K, val: V) -> Option<Box<Node<K,V>>> {
    let mut x = x;
    if x.is_none() {
        return Some(Box::new(Node::new(key, val)));
    }
    let cmp = key.cmp(&x.as_ref().unwrap().key);
    match cmp {
        Ordering::Less => {
            let left = x.as_mut().unwrap().left.take();
            x.as_mut().unwrap().left = put(left, key, val)
        },
        Ordering::Greater => {
            let right = x.as_mut().unwrap().right.take();
            x.as_mut().unwrap().right = put(right, key, val)
        },
        Ordering::Equal => {
            x.as_mut().unwrap().val = val
        }
    }
    x
}

pub struct BST<K, V> {
    root: Option<Box<Node<K, V>>>
}

impl<K: Ord, V> ST<K, V> for BST<K, V> {
    fn new() -> BST<K, V> {
        BST { root: None }
    }

    fn get(&self, key: &K) -> Option<&V> {
        let mut x = self.root.as_ref();
        while x.is_some() {
            match key.cmp(&x.unwrap().key) {
                Ordering::Less => {
                    x = x.unwrap().left.as_ref();
                },
                Ordering::Greater => {
                    x = x.unwrap().right.as_ref();
                },
                Ordering::Equal  => {
                    return Some(&x.unwrap().val)
                }
            }
        }
        None
    }

    fn put(&mut self, key: K, val: V) {
        let root = self.root.take();
        self.root = put(root, key, val);
    }

    fn delete(&mut self, key: &K) {
        unimplemented!()
    }

    fn is_empty(&self) -> bool {
        self.root.is_none()
    }
    /// number of key-value pairs in the table
    fn size(&self) -> usize {
        unimplemented!()
    }
}

impl<K: fmt::Debug, V: fmt::Debug> fmt::Debug for BST<K, V> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        if self.root.is_none() {
            write!(f, "<empty tree>")
        } else {
            self.root.as_ref().unwrap().dump(0, f);
            Ok(())
        }
    }
}

#[test]
fn test_binary_search_tree() {
    let mut t = BST::<char, usize>::new();
    for (i, c) in "SEARCHEXAMP".chars().enumerate() {
        t.put(c, i);
    }

    //println!("{:?}", t);
    assert_eq!(t.get('E'),  Some(&6));
}
<|endoftext|>


<commit_before>// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::intrinsics::{prefetch_read_data, prefetch_write_data,
                      prefetch_read_instruction, prefetch_write_instruction};

#[no_mangle]
pub fn check_prefetch_read_data(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 1)
        prefetch_read_data(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 1)
        prefetch_read_data(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 1)
        prefetch_read_data(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 1)
        prefetch_read_data(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_write_data(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 1)
        prefetch_write_data(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 1)
        prefetch_write_data(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 1)
        prefetch_write_data(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 1)
        prefetch_write_data(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_read_instruction(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 0, i32 0)
        prefetch_read_instruction(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 1, i32 0)
        prefetch_read_instruction(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 2, i32 0)
        prefetch_read_instruction(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 0, i32 3, i32 0)
        prefetch_read_instruction(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_write_instruction(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 0, i32 0)
        prefetch_write_instruction(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 1, i32 0)
        prefetch_write_instruction(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 2, i32 0)
        prefetch_write_instruction(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch(i8* %{{.*}}, i32 1, i32 3, i32 0)
        prefetch_write_instruction(data.as_ptr(), 3);
    }
}
<commit_msg>Account for pointer type suffix in prefetch test<commit_after>// compile-flags: -C no-prepopulate-passes

#![crate_type = "lib"]
#![feature(core_intrinsics)]

use std::intrinsics::{prefetch_read_data, prefetch_write_data,
                      prefetch_read_instruction, prefetch_write_instruction};

#[no_mangle]
pub fn check_prefetch_read_data(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 0, i32 1)
        prefetch_read_data(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 1, i32 1)
        prefetch_read_data(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 2, i32 1)
        prefetch_read_data(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 3, i32 1)
        prefetch_read_data(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_write_data(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 0, i32 1)
        prefetch_write_data(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 1, i32 1)
        prefetch_write_data(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 2, i32 1)
        prefetch_write_data(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 3, i32 1)
        prefetch_write_data(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_read_instruction(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 0, i32 0)
        prefetch_read_instruction(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 1, i32 0)
        prefetch_read_instruction(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 2, i32 0)
        prefetch_read_instruction(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 0, i32 3, i32 0)
        prefetch_read_instruction(data.as_ptr(), 3);
    }
}

#[no_mangle]
pub fn check_prefetch_write_instruction(data: &[i8]) {
    unsafe {
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 0, i32 0)
        prefetch_write_instruction(data.as_ptr(), 0);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 1, i32 0)
        prefetch_write_instruction(data.as_ptr(), 1);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 2, i32 0)
        prefetch_write_instruction(data.as_ptr(), 2);
        // CHECK: call void @llvm.prefetch{{.*}}(i8* %{{.*}}, i32 1, i32 3, i32 0)
        prefetch_write_instruction(data.as_ptr(), 3);
    }
}
<|endoftext|>


<commit_before>//! This example shows how to wrap a data structure in a mutex to achieve safe mutability.
#[macro_use(lazy_static)]
extern crate lazy_static;
use std::collections::HashMap;
use std::sync::Mutex;

lazy_static! {
    static ref MUTEX_MAP: Mutex<HashMap<u32, &'static str>> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        Mutex::new(m)
    };
}

fn main() {
    MUTEX_MAP.lock().unwrap().insert(0, "boo");
    println!(
        "The entry for `0` is \"{}\".",
        MUTEX_MAP.lock().unwrap().get(&0).unwrap()
    );
}
<commit_msg>Revert "macro_use instead of use"<commit_after>//! This example shows how to wrap a data structure in a mutex to achieve safe mutability.
extern crate lazy_static;
use lazy_static::lazy_static;
use std::collections::HashMap;
use std::sync::Mutex;

lazy_static! {
    static ref MUTEX_MAP: Mutex<HashMap<u32, &'static str>> = {
        let mut m = HashMap::new();
        m.insert(0, "foo");
        m.insert(1, "bar");
        m.insert(2, "baz");
        Mutex::new(m)
    };
}

fn main() {
    MUTEX_MAP.lock().unwrap().insert(0, "boo");
    println!(
        "The entry for `0` is \"{}\".",
        MUTEX_MAP.lock().unwrap().get(&0).unwrap()
    );
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError::*;

use gdk;
use gtk::{self, WidgetTrait};

use notty::Command;
use notty::terminal::Terminal;

pub struct CommandApplicator {
    rx: Receiver<Command>,
    terminal: Rc<RefCell<Terminal>>,
    canvas: Rc<gtk::DrawingArea>,
}

impl CommandApplicator {

    pub fn new(rx: Receiver<Command>,
               terminal: Rc<RefCell<Terminal>>,
               canvas: Rc<gtk::DrawingArea>) -> CommandApplicator {
        CommandApplicator { rx: rx, terminal: terminal, canvas: canvas }
    }

    pub fn apply(&self) -> gdk::glib::Continue {
        let mut terminal = self.terminal.borrow_mut();
        let mut redraw = false;
        loop {
            match self.rx.try_recv() {
                Ok(cmd)             => {
                    redraw = true;
                    terminal.apply(&cmd).unwrap_or_else(|_| {
                        gtk::main_quit();
                    });
                }
                Err(Disconnected)   => {
                    gtk::main_quit();
                    panic!();
                }
                Err(Empty)          => break,
            }
        }
        if redraw { self.canvas.queue_draw(); }
        gdk::glib::Continue(true)
    }

}

unsafe impl Send for CommandApplicator { }
<commit_msg>Remove unnecessary panic.<commit_after>use std::cell::RefCell;
use std::rc::Rc;
use std::sync::mpsc::Receiver;
use std::sync::mpsc::TryRecvError::*;

use gdk;
use gtk::{self, WidgetTrait};

use notty::Command;
use notty::terminal::Terminal;

pub struct CommandApplicator {
    rx: Receiver<Command>,
    terminal: Rc<RefCell<Terminal>>,
    canvas: Rc<gtk::DrawingArea>,
}

impl CommandApplicator {

    pub fn new(rx: Receiver<Command>,
               terminal: Rc<RefCell<Terminal>>,
               canvas: Rc<gtk::DrawingArea>) -> CommandApplicator {
        CommandApplicator { rx: rx, terminal: terminal, canvas: canvas }
    }

    pub fn apply(&self) -> gdk::glib::Continue {
        let mut terminal = self.terminal.borrow_mut();
        let mut redraw = false;
        loop {
            match self.rx.try_recv() {
                Ok(cmd)             => {
                    redraw = true;
                    terminal.apply(&cmd).unwrap_or_else(|_| {
                        gtk::main_quit();
                    });
                }
                Err(Disconnected)   => {
                    gtk::main_quit();
                }
                Err(Empty)          => break,
            }
        }
        if redraw { self.canvas.queue_draw(); }
        gdk::glib::Continue(true)
    }

}

unsafe impl Send for CommandApplicator { }
<|endoftext|>


<commit_before>pub fn add_two(a: i32) -> i32 {
    a + 2
}

pub fn greeting(name: &str) -> String {
    format!("Hello {}!", name)
}

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

    #[test]
    fn it_add_two() {
        assert_eq!(4, add_two(2));
    }

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`",
            result
        );
    }

    #[test]
    #[should_panic(expected = "index out of bounds")]
    fn index_out_of_bounds() {
        vec![1][5];
    }
}
<commit_msg>add 11.2 Running tests<commit_after>pub fn add_two(a: i32) -> i32 {
    a + 2
}

pub fn greeting(name: &str) -> String {
    format!("Hello {}!", name)
}

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

    #[test]
    fn it_add_two() {
        assert_eq!(4, add_two(2));
    }

    #[test]
    fn greeting_contains_name() {
        let result = greeting("Carol");
        assert!(
            result.contains("Carol"),
            "Greeting did not contain name, value was `{}`",
            result
        );
    }

    #[test]
    #[should_panic(expected = "index out of bounds")]
    fn index_out_of_bounds() {
        vec![1][5];
    }

    #[test]
    #[ignore]
    fn expensive_test() {
        // take an hour to run
    }
}
<|endoftext|>


<commit_before>use std::rc::Rc;
use ast::typed::{Mutability, Signedness, Size, Type, TypeVar};
use super::rollback_map::Map;

#[derive(Debug, Clone)]
enum VarTarget {
    Type(Type),
    UnsizedInt(Signedness),
    Int,
}

pub struct UnifyTable {
    var_target: Map<TypeVar, VarTarget>,
    next_var: u32,
}

impl UnifyTable {
    pub fn new() -> UnifyTable {
        UnifyTable {
            var_target: Map::new(),
            next_var: 0,
        }
    }

    pub fn fresh_var(&mut self) -> TypeVar {
        let var = TypeVar(self.next_var);
        self.next_var += 1;
        var
    }

    pub fn fresh_int_var(&mut self, sign: Option<Signedness>) -> TypeVar {
        let var = TypeVar(self.next_var);
        match sign {
            Some(sign) => self.var_target.insert(var, VarTarget::UnsizedInt(sign)),
            None => self.var_target.insert(var, VarTarget::Int),
        }
        self.var_target.commit();
        self.next_var += 1;
        var
    }

    pub fn unify(&mut self, a: &Type, b: &Type) -> Result<Type, ()> {
        match self.unify_raw(a, b, true) {
            Ok(()) => {
                self.commit();
                Ok(a.clone())
            }
            Err(()) => {
                self.rollback();
                Err(())
            }
        }
    }

    fn unify_raw(&mut self, a: &Type, b: &Type, allow_coerce: bool) -> Result<(), ()> {
        let a = self.shallow_normalize(a);
        let b = self.shallow_normalize(b);
        match (a, b) {
            (Type::Concrete(a, ref ap), Type::Concrete(b, ref bp)) => if a == b {
                assert_eq!(ap.len(), bp.len());
                for (a, b) in ap.iter().zip(bp.iter()) {
                    self.unify_raw(a, b, false)?;
                }
                Ok(())
            } else {
                Err(())
            },
            (Type::Function(ref ap, ref a), Type::Function(ref bp, ref b)) => {
                if ap.len() == bp.len() {
                    for (a, b) in ap.iter().zip(bp.iter()) {
                        // flip `a` and `b` when unifying because fns are
                        // contravariant on their arguments - so we can only
                        // coerce types backwards.
                        self.unify_raw(b, a, true)?;
                    }
                    self.unify_raw(a, b, true)
                } else {
                    Err(())
                }
            }
            (Type::Int(sign1, size1), Type::Int(sign2, size2)) => {
                if sign1 == sign2 && size1 == size2 {
                    Ok(())
                } else {
                    Err(())
                }
            }
            (Type::Pointer(m1, ref a), Type::Pointer(m2, ref b)) if m1 == m2 => {
                self.unify_raw(a, b, false)
            }
            (Type::Pointer(Mutability::Mut, ref a), Type::Pointer(Mutability::Const, ref b))
            if allow_coerce => {
                self.unify_raw(a, b, false)
            }
            (Type::Var(a), ty) | (ty, Type::Var(a)) => self.unify_var_type(a, ty),
            (Type::Bool, Type::Bool) |
            (Type::Unit, Type::Unit) |
            (Type::Error, _) | (_, Type::Error) => Ok(()),
            (_, _) => Err(()),
        }
    }

    fn unify_var_var(&mut self, a: TypeVar, b: TypeVar) -> Result<(), ()> {
        let at = self.var_target.get(&a).cloned();
        let bt = self.var_target.get(&b).cloned();
        match (at, bt) {
            (Some(VarTarget::Type(_)), _) | (_, Some(VarTarget::Type(_))) => {
                panic!("cannot unify non-normalized var")
            }
            (None, _) | (Some(VarTarget::Int), Some(_)) => {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            }
            (_, None) | (Some(_), Some(VarTarget::Int)) => {
                self.var_target.insert(b, VarTarget::Type(Type::Var(a)));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(s1)), Some(VarTarget::UnsizedInt(s2))) => if s1 == s2 {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            } else {
                Err(())
            },
        }
    }

    fn unify_var_type(&mut self, v: TypeVar, b: Type) -> Result<(), ()> {
        match b {
            Type::Var(b) if b == v => return Ok(()),
            _ => {}
        }
        if self.occurs(v, &b) {
            return Err(());
        }
        let vt = self.var_target.get(&v).cloned();
        match (vt, b) {
            (_, Type::Error) => {
                self.var_target.insert(v, VarTarget::Type(Type::Error));
                Ok(())
            }
            (Some(VarTarget::Type(_)), _) => panic!("cannot unify non-normalized var"),
            (_, Type::Var(b)) => self.unify_var_var(v, b),
            (None, ty) | (Some(VarTarget::Int), ty @ Type::Int(_, _)) => {
                self.var_target.insert(v, VarTarget::Type(ty));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(sign)), Type::Int(sign2, size)) => if sign == sign2 {
                self.var_target
                    .insert(v, VarTarget::Type(Type::Int(sign2, size)));
                Ok(())
            } else {
                Err(())
            },
            _ => Err(()),
        }
    }

    fn occurs(&mut self, var: TypeVar, typ: &Type) -> bool {
        let typ = self.shallow_normalize(typ);
        match typ {
            Type::Bool | Type::Error | Type::Int(_, _) | Type::Unit => false,
            Type::Concrete(_, ref params) => {
                for param in params.iter() {
                    if self.occurs(var, param) {
                        return true;
                    }
                }
                false
            }
            Type::Function(ref params, ref out) => {
                for param in params.iter() {
                    if self.occurs(var, param) {
                        return true;
                    }
                }
                self.occurs(var, out)
            }
            Type::Pointer(_, ref to) => self.occurs(var, to),
            Type::Var(v) => var == v,
        }
    }

    fn get_var_type(&self, var: TypeVar) -> Type {
        match self.var_target.get(&var) {
            Some(&VarTarget::Type(ref ty)) => self.shallow_normalize(ty),
            Some(&VarTarget::Int) | Some(&VarTarget::UnsizedInt(_)) | None => Type::Var(var),
        }
    }

    pub fn shallow_normalize(&self, a: &Type) -> Type {
        match a {
            &Type::Var(var) => self.get_var_type(var),
            ty => ty.clone(),
        }
    }

    pub fn normalize(&mut self, a: &Type) -> Result<Type, ()> {
        match self.shallow_normalize(a) {
            Type::Bool => Ok(Type::Bool),
            Type::Unit => Ok(Type::Unit),
            Type::Concrete(sym, ref params) => {
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Concrete(sym, normalized.into()))
            }
            Type::Error => Ok(Type::Error),
            Type::Function(ref params, ref out) => {
                let out = self.normalize(out)?;
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Function(normalized.into(), Rc::new(out)))
            }
            ty @ Type::Int(_, _) => Ok(ty),
            Type::Pointer(mutability, ref ty) => {
                let ty = self.normalize(ty)?;
                Ok(Type::Pointer(mutability, Rc::new(ty)))
            }
            Type::Var(var) => {
                match self.var_target.get(&var) {
                    Some(&VarTarget::Type(_)) => panic!("var not normalized"),
                    Some(&VarTarget::Int) => {
                        return Ok(Type::Int(Signedness::Signed, Size::Bit32));
                    }
                    Some(&VarTarget::UnsizedInt(sign)) => {
                        return Ok(Type::Int(sign, Size::Bit32));
                    }
                    None => {
                        // there is no sensible default
                        // fall though because of borrowck
                    }
                }
                // unify this var with an error to prevent further
                // error reports about same variable
                self.var_target.insert(var, VarTarget::Type(Type::Error));
                Err(())
            }
        }
    }

    pub fn describe_var(&self, var: TypeVar) -> &'static str {
        match self.var_target.get(&var) {
            Some(&VarTarget::Int) => "{int}",
            Some(&VarTarget::UnsizedInt(Signedness::Signed)) => "{signed}",
            Some(&VarTarget::UnsizedInt(Signedness::Unsigned)) => "{unsigned}",
            _ => "_",
        }
    }

    fn commit(&mut self) {
        self.var_target.commit();
    }

    fn rollback(&mut self) {
        self.var_target.rollback();
    }
}
<commit_msg>fix inference results when coercing<commit_after>use std::rc::Rc;
use ast::typed::{Mutability, Signedness, Size, Type, TypeVar};
use super::rollback_map::Map;

#[derive(Debug, Clone)]
enum VarTarget {
    Type(Type),
    UnsizedInt(Signedness),
    Int,
}

pub struct UnifyTable {
    var_target: Map<TypeVar, VarTarget>,
    next_var: u32,
}

impl UnifyTable {
    pub fn new() -> UnifyTable {
        UnifyTable {
            var_target: Map::new(),
            next_var: 0,
        }
    }

    pub fn fresh_var(&mut self) -> TypeVar {
        let var = TypeVar(self.next_var);
        self.next_var += 1;
        var
    }

    pub fn fresh_int_var(&mut self, sign: Option<Signedness>) -> TypeVar {
        let var = TypeVar(self.next_var);
        match sign {
            Some(sign) => self.var_target.insert(var, VarTarget::UnsizedInt(sign)),
            None => self.var_target.insert(var, VarTarget::Int),
        }
        self.var_target.commit();
        self.next_var += 1;
        var
    }

    pub fn unify(&mut self, a: &Type, b: &Type) -> Result<Type, ()> {
        match self.unify_raw(a, b, true) {
            Ok(()) => {
                self.commit();
                // `a` might get coerced to `b`, so we return `b` as result
                Ok(b.clone())
            }
            Err(()) => {
                self.rollback();
                Err(())
            }
        }
    }

    fn unify_raw(&mut self, a: &Type, b: &Type, allow_coerce: bool) -> Result<(), ()> {
        let a = self.shallow_normalize(a);
        let b = self.shallow_normalize(b);
        match (a, b) {
            (Type::Concrete(a, ref ap), Type::Concrete(b, ref bp)) => if a == b {
                assert_eq!(ap.len(), bp.len());
                for (a, b) in ap.iter().zip(bp.iter()) {
                    self.unify_raw(a, b, false)?;
                }
                Ok(())
            } else {
                Err(())
            },
            (Type::Function(ref ap, ref a), Type::Function(ref bp, ref b)) => {
                if ap.len() == bp.len() {
                    for (a, b) in ap.iter().zip(bp.iter()) {
                        // flip `a` and `b` when unifying because fns are
                        // contravariant on their arguments - so we can only
                        // coerce types backwards.
                        self.unify_raw(b, a, true)?;
                    }
                    self.unify_raw(a, b, true)
                } else {
                    Err(())
                }
            }
            (Type::Int(sign1, size1), Type::Int(sign2, size2)) => {
                if sign1 == sign2 && size1 == size2 {
                    Ok(())
                } else {
                    Err(())
                }
            }
            (Type::Pointer(m1, ref a), Type::Pointer(m2, ref b)) if m1 == m2 => {
                self.unify_raw(a, b, false)
            }
            (Type::Pointer(Mutability::Mut, ref a), Type::Pointer(Mutability::Const, ref b))
            if allow_coerce => {
                self.unify_raw(a, b, false)
            }
            (Type::Var(a), ty) | (ty, Type::Var(a)) => self.unify_var_type(a, ty),
            (Type::Bool, Type::Bool) |
            (Type::Unit, Type::Unit) |
            (Type::Error, _) | (_, Type::Error) => Ok(()),
            (_, _) => Err(()),
        }
    }

    fn unify_var_var(&mut self, a: TypeVar, b: TypeVar) -> Result<(), ()> {
        let at = self.var_target.get(&a).cloned();
        let bt = self.var_target.get(&b).cloned();
        match (at, bt) {
            (Some(VarTarget::Type(_)), _) | (_, Some(VarTarget::Type(_))) => {
                panic!("cannot unify non-normalized var")
            }
            (None, _) | (Some(VarTarget::Int), Some(_)) => {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            }
            (_, None) | (Some(_), Some(VarTarget::Int)) => {
                self.var_target.insert(b, VarTarget::Type(Type::Var(a)));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(s1)), Some(VarTarget::UnsizedInt(s2))) => if s1 == s2 {
                self.var_target.insert(a, VarTarget::Type(Type::Var(b)));
                Ok(())
            } else {
                Err(())
            },
        }
    }

    fn unify_var_type(&mut self, v: TypeVar, b: Type) -> Result<(), ()> {
        match b {
            Type::Var(b) if b == v => return Ok(()),
            _ => {}
        }
        if self.occurs(v, &b) {
            return Err(());
        }
        let vt = self.var_target.get(&v).cloned();
        match (vt, b) {
            (_, Type::Error) => {
                self.var_target.insert(v, VarTarget::Type(Type::Error));
                Ok(())
            }
            (Some(VarTarget::Type(_)), _) => panic!("cannot unify non-normalized var"),
            (_, Type::Var(b)) => self.unify_var_var(v, b),
            (None, ty) | (Some(VarTarget::Int), ty @ Type::Int(_, _)) => {
                self.var_target.insert(v, VarTarget::Type(ty));
                Ok(())
            }
            (Some(VarTarget::UnsizedInt(sign)), Type::Int(sign2, size)) => if sign == sign2 {
                self.var_target
                    .insert(v, VarTarget::Type(Type::Int(sign2, size)));
                Ok(())
            } else {
                Err(())
            },
            _ => Err(()),
        }
    }

    fn occurs(&mut self, var: TypeVar, typ: &Type) -> bool {
        let typ = self.shallow_normalize(typ);
        match typ {
            Type::Bool | Type::Error | Type::Int(_, _) | Type::Unit => false,
            Type::Concrete(_, ref params) => {
                for param in params.iter() {
                    if self.occurs(var, param) {
                        return true;
                    }
                }
                false
            }
            Type::Function(ref params, ref out) => {
                for param in params.iter() {
                    if self.occurs(var, param) {
                        return true;
                    }
                }
                self.occurs(var, out)
            }
            Type::Pointer(_, ref to) => self.occurs(var, to),
            Type::Var(v) => var == v,
        }
    }

    fn get_var_type(&self, var: TypeVar) -> Type {
        match self.var_target.get(&var) {
            Some(&VarTarget::Type(ref ty)) => self.shallow_normalize(ty),
            Some(&VarTarget::Int) | Some(&VarTarget::UnsizedInt(_)) | None => Type::Var(var),
        }
    }

    pub fn shallow_normalize(&self, a: &Type) -> Type {
        match a {
            &Type::Var(var) => self.get_var_type(var),
            ty => ty.clone(),
        }
    }

    pub fn normalize(&mut self, a: &Type) -> Result<Type, ()> {
        match self.shallow_normalize(a) {
            Type::Bool => Ok(Type::Bool),
            Type::Unit => Ok(Type::Unit),
            Type::Concrete(sym, ref params) => {
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Concrete(sym, normalized.into()))
            }
            Type::Error => Ok(Type::Error),
            Type::Function(ref params, ref out) => {
                let out = self.normalize(out)?;
                let mut normalized = Vec::new();
                for param in &**params {
                    normalized.push(self.normalize(param)?);
                }
                Ok(Type::Function(normalized.into(), Rc::new(out)))
            }
            ty @ Type::Int(_, _) => Ok(ty),
            Type::Pointer(mutability, ref ty) => {
                let ty = self.normalize(ty)?;
                Ok(Type::Pointer(mutability, Rc::new(ty)))
            }
            Type::Var(var) => {
                match self.var_target.get(&var) {
                    Some(&VarTarget::Type(_)) => panic!("var not normalized"),
                    Some(&VarTarget::Int) => {
                        return Ok(Type::Int(Signedness::Signed, Size::Bit32));
                    }
                    Some(&VarTarget::UnsizedInt(sign)) => {
                        return Ok(Type::Int(sign, Size::Bit32));
                    }
                    None => {
                        // there is no sensible default
                        // fall though because of borrowck
                    }
                }
                // unify this var with an error to prevent further
                // error reports about same variable
                self.var_target.insert(var, VarTarget::Type(Type::Error));
                Err(())
            }
        }
    }

    pub fn describe_var(&self, var: TypeVar) -> &'static str {
        match self.var_target.get(&var) {
            Some(&VarTarget::Int) => "{int}",
            Some(&VarTarget::UnsizedInt(Signedness::Signed)) => "{signed}",
            Some(&VarTarget::UnsizedInt(Signedness::Unsigned)) => "{unsigned}",
            _ => "_",
        }
    }

    fn commit(&mut self) {
        self.var_target.commit();
    }

    fn rollback(&mut self) {
        self.var_target.rollback();
    }
}
<|endoftext|>


<commit_before>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
use std::process;

fn attack_cipher(ciphertext: Vec<u8>, crib: Vec<u8>) {
    for (i, x) in ciphertext.iter().enumerate() {
        let mut old_key = x ^ crib[0];
        let mut j = 1;
        while j < crib.len() && (i+j) < ciphertext.len() {
            let key = ciphertext[i+j] ^ crib[j];
            if key != old_key { break; }
            old_key = key;
            j += 1;
            if j == crib.len() {
                println!("Found text at 0x{:x} (XOR key 0x{:02x})", i, key);
                print!("  preview: ");
                let preview: String = ciphertext[i..i+50]
                    .iter()
                    .map(|x| x ^ key)
                    .map(|x| if x >= 32 && x <= 126 {x as char} else {'.'})
                    .collect();
                println!("{}", preview);
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().collect();
    if args.len() < 3 {
        println!("usage: roxor <file> <crib>");
        process::exit(1);
    }

    let path = Path::new(&args[1]);
    let crib: Vec<u8> = args[2].bytes().collect();

    if crib.len() < 2 {
        println!("error: crib too short");
        process::exit(1);
    }

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), Error::description(&why)),
        Ok(file) => file,
    };

    let mut ciphertext: Vec<u8> = Vec::new();
    file.read_to_end(&mut ciphertext).unwrap();

    if ciphertext.len() < crib.len() {
        println!("error: ciphertext too short");
        process::exit(1);
    }

    attack_cipher(ciphertext, crib);
}
<commit_msg>Write to stderr<commit_after>use std::env;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;
use std::io::stderr;
use std::path::Path;
use std::process;

fn attack_cipher(ciphertext: Vec<u8>, crib: Vec<u8>) {
    for (i, x) in ciphertext.iter().enumerate() {
        let mut old_key = x ^ crib[0];
        let mut j = 1;
        while j < crib.len() && (i+j) < ciphertext.len() {
            let key = ciphertext[i+j] ^ crib[j];
            if key != old_key { break; }
            old_key = key;
            j += 1;
            if j == crib.len() {
                println!("Found text at 0x{:x} (XOR key 0x{:02x})", i, key);
                print!("  preview: ");
                let preview: String = ciphertext[i..i+50]
                    .iter()
                    .map(|x| x ^ key)
                    .map(|x| if x >= 32 && x <= 126 {x as char} else {'.'})
                    .collect();
                println!("{}", preview);
            }
        }
    }
}

fn main() {
    let args: Vec<String> = env::args().skip(1).collect();
    if args.len() < 2 {
        writeln!(stderr(), "usage: roxor <file> <crib>").unwrap();
        process::exit(1);
    }

    let path = Path::new(&args[0]);
    let crib: Vec<u8> = args[1].bytes().collect();

    if crib.len() < 2 {
        writeln!(stderr(), "error: crib too short").unwrap();
        process::exit(1);
    }

    let mut file = match File::open(&path) {
        Err(why) => panic!("couldn't open {}: {}", path.display(), Error::description(&why)),
        Ok(file) => file,
    };

    let mut ciphertext: Vec<u8> = Vec::new();
    file.read_to_end(&mut ciphertext).unwrap();

    if ciphertext.len() < crib.len() {
        writeln!(stderr(), "error: ciphertext too short").unwrap();
        process::exit(1);
    }

    attack_cipher(ciphertext, crib);
}
<|endoftext|>


<commit_before>// Copyright 2012-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.
pub use self::MaybeTyped::*;

use rustc_trans::driver::driver;
use rustc::session::{mod, config};
use rustc::middle::{privacy, ty};
use rustc::lint;
use rustc_trans::back::link;

use syntax::{ast, ast_map, codemap, diagnostic};

use std::cell::RefCell;
use std::os;
use std::collections::{HashMap, HashSet};
use arena::TypedArena;

use visit_ast::RustdocVisitor;
use clean;
use clean::Clean;

/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
pub enum MaybeTyped<'tcx> {
    Typed(ty::ctxt<'tcx>),
    NotTyped(session::Session)
}

pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
                                                (Vec<String>, clean::TypeKind)>>>;

pub struct DocContext<'tcx> {
    pub krate: &'tcx ast::Crate,
    pub maybe_typed: MaybeTyped<'tcx>,
    pub src: Path,
    pub external_paths: ExternalPaths,
    pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
    pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
    pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
    pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
}

impl<'tcx> DocContext<'tcx> {
    pub fn sess<'a>(&'a self) -> &'a session::Session {
        match self.maybe_typed {
            Typed(ref tcx) => &tcx.sess,
            NotTyped(ref sess) => sess
        }
    }

    pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
        match self.maybe_typed {
            Typed(ref tcx) => Some(tcx),
            NotTyped(_) => None
        }
    }

    pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
        let tcx_opt = self.tcx_opt();
        tcx_opt.expect("tcx not present")
    }
}

pub struct CrateAnalysis {
    pub exported_items: privacy::ExportedItems,
    pub public_items: privacy::PublicItems,
    pub external_paths: ExternalPaths,
    pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
    pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
    pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
}

pub type Externs = HashMap<String, Vec<String>>;

pub fn run_core(libs: Vec<Path>, cfgs: Vec<String>, externs: Externs,
                cpath: &Path, triple: Option<String>)
                -> (clean::Crate, CrateAnalysis) {

    // Parse, resolve, and typecheck the given crate.

    let input = driver::FileInput(cpath.clone());

    let warning_lint = lint::builtin::WARNINGS.name_lower();

    let sessopts = config::Options {
        maybe_sysroot: Some(os::self_exe_path().unwrap().dir_path()),
        addl_lib_search_paths: RefCell::new(libs),
        crate_types: vec!(config::CrateTypeRlib),
        lint_opts: vec!((warning_lint, lint::Allow)),
        externs: externs,
        target_triple: triple.unwrap_or(config::host_triple().to_string()),
        cfg: config::parse_cfgspecs(cfgs),
        ..config::basic_options().clone()
    };

    let codemap = codemap::CodeMap::new();
    let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, codemap);

    let sess = session::build_session_(sessopts,
                                       Some(cpath.clone()),
                                       span_diagnostic_handler);

    let cfg = config::build_configuration(&sess);

    let krate = driver::phase_1_parse_input(&sess, cfg, &input);

    let name = link::find_crate_name(Some(&sess), krate.attrs.as_slice(),
                                     &input);

    let krate = driver::phase_2_configure_and_expand(&sess, krate, name.as_slice(), None)
                    .expect("phase_2_configure_and_expand aborted in rustdoc!");

    let mut forest = ast_map::Forest::new(krate);
    let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);

    let type_arena = TypedArena::new();
    let driver::CrateAnalysis {
        exported_items, public_items, ty_cx, ..
    } = driver::phase_3_run_analysis_passes(sess, ast_map, &type_arena, name);

    let ctxt = DocContext {
        krate: ty_cx.map.krate(),
        maybe_typed: Typed(ty_cx),
        src: cpath.clone(),
        external_traits: RefCell::new(Some(HashMap::new())),
        external_typarams: RefCell::new(Some(HashMap::new())),
        external_paths: RefCell::new(Some(HashMap::new())),
        inlined: RefCell::new(Some(HashSet::new())),
        populated_crate_impls: RefCell::new(HashSet::new()),
    };
    debug!("crate: {}", ctxt.krate);

    let analysis = CrateAnalysis {
        exported_items: exported_items,
        public_items: public_items,
        external_paths: RefCell::new(None),
        external_traits: RefCell::new(None),
        external_typarams: RefCell::new(None),
        inlined: RefCell::new(None),
    };

    let krate = {
        let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
        v.visit(ctxt.krate);
        v.clean(&ctxt)
    };

    let external_paths = ctxt.external_paths.borrow_mut().take();
    *analysis.external_paths.borrow_mut() = external_paths;
    let map = ctxt.external_traits.borrow_mut().take();
    *analysis.external_traits.borrow_mut() = map;
    let map = ctxt.external_typarams.borrow_mut().take();
    *analysis.external_typarams.borrow_mut() = map;
    let map = ctxt.inlined.borrow_mut().take();
    *analysis.inlined.borrow_mut() = map;
    (krate, analysis)
}
<commit_msg>rustdoc: avoid supplying a bad default sysroot so the librustc code can calculate it properly<commit_after>// Copyright 2012-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.
pub use self::MaybeTyped::*;

use rustc_trans::driver::driver;
use rustc::session::{mod, config};
use rustc::middle::{privacy, ty};
use rustc::lint;
use rustc_trans::back::link;

use syntax::{ast, ast_map, codemap, diagnostic};

use std::cell::RefCell;
use std::collections::{HashMap, HashSet};
use arena::TypedArena;

use visit_ast::RustdocVisitor;
use clean;
use clean::Clean;

/// Are we generating documentation (`Typed`) or tests (`NotTyped`)?
pub enum MaybeTyped<'tcx> {
    Typed(ty::ctxt<'tcx>),
    NotTyped(session::Session)
}

pub type ExternalPaths = RefCell<Option<HashMap<ast::DefId,
                                                (Vec<String>, clean::TypeKind)>>>;

pub struct DocContext<'tcx> {
    pub krate: &'tcx ast::Crate,
    pub maybe_typed: MaybeTyped<'tcx>,
    pub src: Path,
    pub external_paths: ExternalPaths,
    pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
    pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
    pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
    pub populated_crate_impls: RefCell<HashSet<ast::CrateNum>>,
}

impl<'tcx> DocContext<'tcx> {
    pub fn sess<'a>(&'a self) -> &'a session::Session {
        match self.maybe_typed {
            Typed(ref tcx) => &tcx.sess,
            NotTyped(ref sess) => sess
        }
    }

    pub fn tcx_opt<'a>(&'a self) -> Option<&'a ty::ctxt<'tcx>> {
        match self.maybe_typed {
            Typed(ref tcx) => Some(tcx),
            NotTyped(_) => None
        }
    }

    pub fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> {
        let tcx_opt = self.tcx_opt();
        tcx_opt.expect("tcx not present")
    }
}

pub struct CrateAnalysis {
    pub exported_items: privacy::ExportedItems,
    pub public_items: privacy::PublicItems,
    pub external_paths: ExternalPaths,
    pub external_traits: RefCell<Option<HashMap<ast::DefId, clean::Trait>>>,
    pub external_typarams: RefCell<Option<HashMap<ast::DefId, String>>>,
    pub inlined: RefCell<Option<HashSet<ast::DefId>>>,
}

pub type Externs = HashMap<String, Vec<String>>;

pub fn run_core(libs: Vec<Path>, cfgs: Vec<String>, externs: Externs,
                cpath: &Path, triple: Option<String>)
                -> (clean::Crate, CrateAnalysis) {

    // Parse, resolve, and typecheck the given crate.

    let input = driver::FileInput(cpath.clone());

    let warning_lint = lint::builtin::WARNINGS.name_lower();

    let sessopts = config::Options {
        maybe_sysroot: None,
        addl_lib_search_paths: RefCell::new(libs),
        crate_types: vec!(config::CrateTypeRlib),
        lint_opts: vec!((warning_lint, lint::Allow)),
        externs: externs,
        target_triple: triple.unwrap_or(config::host_triple().to_string()),
        cfg: config::parse_cfgspecs(cfgs),
        ..config::basic_options().clone()
    };

    let codemap = codemap::CodeMap::new();
    let diagnostic_handler = diagnostic::default_handler(diagnostic::Auto, None);
    let span_diagnostic_handler =
        diagnostic::mk_span_handler(diagnostic_handler, codemap);

    let sess = session::build_session_(sessopts,
                                       Some(cpath.clone()),
                                       span_diagnostic_handler);

    let cfg = config::build_configuration(&sess);

    let krate = driver::phase_1_parse_input(&sess, cfg, &input);

    let name = link::find_crate_name(Some(&sess), krate.attrs.as_slice(),
                                     &input);

    let krate = driver::phase_2_configure_and_expand(&sess, krate, name.as_slice(), None)
                    .expect("phase_2_configure_and_expand aborted in rustdoc!");

    let mut forest = ast_map::Forest::new(krate);
    let ast_map = driver::assign_node_ids_and_map(&sess, &mut forest);

    let type_arena = TypedArena::new();
    let driver::CrateAnalysis {
        exported_items, public_items, ty_cx, ..
    } = driver::phase_3_run_analysis_passes(sess, ast_map, &type_arena, name);

    let ctxt = DocContext {
        krate: ty_cx.map.krate(),
        maybe_typed: Typed(ty_cx),
        src: cpath.clone(),
        external_traits: RefCell::new(Some(HashMap::new())),
        external_typarams: RefCell::new(Some(HashMap::new())),
        external_paths: RefCell::new(Some(HashMap::new())),
        inlined: RefCell::new(Some(HashSet::new())),
        populated_crate_impls: RefCell::new(HashSet::new()),
    };
    debug!("crate: {}", ctxt.krate);

    let analysis = CrateAnalysis {
        exported_items: exported_items,
        public_items: public_items,
        external_paths: RefCell::new(None),
        external_traits: RefCell::new(None),
        external_typarams: RefCell::new(None),
        inlined: RefCell::new(None),
    };

    let krate = {
        let mut v = RustdocVisitor::new(&ctxt, Some(&analysis));
        v.visit(ctxt.krate);
        v.clean(&ctxt)
    };

    let external_paths = ctxt.external_paths.borrow_mut().take();
    *analysis.external_paths.borrow_mut() = external_paths;
    let map = ctxt.external_traits.borrow_mut().take();
    *analysis.external_traits.borrow_mut() = map;
    let map = ctxt.external_typarams.borrow_mut().take();
    *analysis.external_typarams.borrow_mut() = map;
    let map = ctxt.inlined.borrow_mut().take();
    *analysis.inlined.borrow_mut() = map;
    (krate, analysis)
}
<|endoftext|>