<commit_before>use std::cmp::Ordering;
use std::{mem};

// Bounded package merge algorithm, based on the paper
// "A Fast and Space-Economical Algorithm for Length-Limited Coding
// Jyrki Katajainen, Alistair Moffat, Andrew Turpin".

#[derive(Debug)]
struct Node {
    weight: usize,
    leaf_counts: Vec<i32>,
}

impl Node {
    fn new(weight: usize, initial_count: i32, capacity: usize) -> Node {
        let mut n = Node {
            weight: weight,
            leaf_counts: Vec::with_capacity(capacity),
        };
        n.leaf_counts.push(initial_count);
        n
    }
}

#[derive(Debug)]
struct Leaf {
    weight: usize,
    index: usize,
}
impl PartialEq for Leaf {
    fn eq(&self, other: &Self) -> bool {
        self.weight == other.weight
    }
}
impl Eq for Leaf { }
impl Ord for Leaf {
    fn cmp(&self, other: &Self) -> Ordering {
        self.weight.cmp(&other.weight)
    }
}
impl PartialOrd for Leaf {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[derive(Debug)]
struct List {
    lookahead1: Node,
    lookahead2: Node,
    next_leaf_index: usize,
}

/// Calculates the bitlengths for the Huffman tree, based on the counts of each
/// symbol.
pub fn length_limited_code_lengths(frequencies: &[usize], maxbits: i32) -> Vec<u32> {
    let mut leaves = vec![];

    // Count used symbols and place them in the leaves.
    for (i, &freq) in frequencies.iter().enumerate() {
        if freq != 0 {
            leaves.push(Leaf { weight: freq, index: i });
        }
    }

    // Short circuit some special cases
    if leaves.is_empty() {
        // There are no non-zero frequencies.
        return vec![0; frequencies.len()];
    }
    if leaves.len() == 1 {
        let mut result = vec![0; frequencies.len()];
        result[leaves[0].index] = 1;
        return result;
    }
    if leaves.len() == 2 {
        let mut result = vec![0; frequencies.len()];
        result[leaves[0].index] = 1;
        result[leaves[1].index] = 1;
        return result;
    }

    // Sort the leaves from least frequent to most frequent.
    // Add index into the same variable for stable sorting.
    for leaf in &mut leaves {
        leaf.weight = (leaf.weight << 9) | leaf.index;
    }
    leaves.sort();
    for leaf in &mut leaves {
        leaf.weight >>= 9;
    }

    let max_num_leaves = 2 * leaves.len() - 2;

    let mut lists = Vec::with_capacity(maxbits as usize);
    for _ in 0..maxbits {
        lists.push(List {
            lookahead1: Node::new(leaves[0].weight, 1, max_num_leaves),
            lookahead2: Node::new(leaves[1].weight, 2, max_num_leaves),
            next_leaf_index: 2,
        });
    }

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each boundary_pm run creates one.
    let num_boundary_pm_runs = max_num_leaves - 2;
    for _ in 0..num_boundary_pm_runs {
        boundary_pm_toplevel(&mut lists[..], &leaves);
    }

    let n = frequencies.len();
    let mut result = vec![0; n];

    let mut a = lists.pop().unwrap().lookahead2.leaf_counts.into_iter().rev().peekable();

    let mut bitlength_value = 1;
    while let Some(leaf_count) = a.next() {
        let next_count = *a.peek().unwrap_or(&0);
        for leaf in &leaves[next_count as usize..leaf_count as usize] {
            result[leaf.index] = bitlength_value;
        }
        bitlength_value += 1;
    }

    result
}

fn lowest_list(lists: &mut [List], leaves: &[Leaf]) {
    // We're in the lowest list, just add another leaf to the lookaheads
    // There will always be more leaves to be added on level 0 so this is safe.
    let mut current_list = lists.get_mut(0).unwrap();
    let next_leaf = &leaves[current_list.next_leaf_index];
    current_list.lookahead2.weight = next_leaf.weight;

    current_list.lookahead2.leaf_counts[0] = current_list.lookahead1.leaf_counts.last().unwrap() + 1;
    current_list.next_leaf_index += 1;
}

fn next_leaf(lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    let mut current_list = lists.get_mut(current_list_index).unwrap();

    // The next leaf goes next; counting itself makes the leaf_count increase by one.
    current_list.lookahead2.weight = leaves[current_list.next_leaf_index].weight;
    current_list.lookahead2.leaf_counts.clear();
    current_list.lookahead2.leaf_counts.extend_from_slice(&current_list.lookahead1.leaf_counts);
    let last_index = current_list.lookahead2.leaf_counts.len() - 1;
    current_list.lookahead2.leaf_counts[last_index] += 1;
    current_list.next_leaf_index += 1;
}

fn next_tree(weight_sum: usize, lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    {
        let (head, tail) = lists.split_at_mut(current_list_index);
        let prev_list = head.last_mut().unwrap();
        let current_list = tail.first_mut().unwrap();

        let previous_list_leaf_counts = &prev_list.lookahead2.leaf_counts;

        // Make a tree from the lookaheads from the previous list; that goes next.
        // This is not a leaf node, so the leaf count stays the same.
        current_list.lookahead2.weight = weight_sum;
        current_list.lookahead2.leaf_counts.clear();

        current_list.lookahead2.leaf_counts.extend_from_slice(previous_list_leaf_counts);
        current_list.lookahead2.leaf_counts.push(*current_list.lookahead1.leaf_counts.last().unwrap());
    }

    // The previous list needs two new lookahead nodes.
    boundary_pm(lists, leaves, current_list_index - 1);
    boundary_pm(lists, leaves, current_list_index - 1);
}

fn boundary_pm_toplevel(lists: &mut [List], leaves: &[Leaf]) {
    let last_index = lists.len() - 1;
    boundary_pm(lists, leaves, last_index);
}

fn boundary_pm(lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    let next_leaf_index = lists[current_list_index].next_leaf_index;

    if current_list_index == 0 && next_leaf_index == leaves.len() {
        // We've added all the leaves to the lowest list, so we're done here
        return;
    }

    mem::swap(&mut lists[current_list_index].lookahead1, &mut lists[current_list_index].lookahead2);

    if current_list_index == 0 {
        lowest_list(lists, leaves);
    } else {
        // We're at a list other than the lowest list.
        let weight_sum = {
            let previous_list = lists.get(current_list_index - 1).unwrap();
            previous_list.lookahead1.weight + previous_list.lookahead2.weight
        };

        if next_leaf_index < leaves.len() && weight_sum > leaves[next_leaf_index].weight {
            next_leaf(lists, leaves, current_list_index);
        } else {
            next_tree(weight_sum, lists, leaves, current_list_index);
        }
    }
}

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

    #[test]
    fn test_from_paper_3() {
        let input = [1, 1, 5, 7, 10, 14];
        let output = length_limited_code_lengths(&input, 3);
        let answer = vec![3, 3, 3, 3, 2, 2];
        assert_eq!(output, answer);
    }

    #[test]
    fn test_from_paper_4() {
        let input = [1, 1, 5, 7, 10, 14];
        let output = length_limited_code_lengths(&input, 4);
        let answer = vec![4, 4, 3, 2, 2, 2];
        assert_eq!(output, answer);
    }

    #[test]
    fn maxbits_7() {
        let input = [252, 0, 1, 6, 9, 10, 6, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![1, 0, 6, 4, 3, 3, 3, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn maxbits_15() {
        let input = [0, 0, 0, 0, 0, 0, 18, 0, 6, 0, 12, 2, 14, 9, 27, 15, 23, 15, 17, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 15);
        let answer = vec! [0, 0, 0, 0, 0, 0, 3, 0, 5, 0, 4, 6, 4, 4, 3, 4, 3, 3, 3, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn no_frequencies() {
        let input = [0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn only_one_frequency() {
        let input = [0, 10, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![0, 1, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn only_two_frequencies() {
        let input = [0, 0, 0, 0, 252, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }
}
<commit_msg>Counts should be usizes imo<commit_after>use std::cmp::Ordering;
use std::{mem};

// Bounded package merge algorithm, based on the paper
// "A Fast and Space-Economical Algorithm for Length-Limited Coding
// Jyrki Katajainen, Alistair Moffat, Andrew Turpin".

#[derive(Debug)]
struct Node {
    weight: usize,
    leaf_counts: Vec<usize>,
}

impl Node {
    fn new(weight: usize, initial_count: usize, capacity: usize) -> Node {
        let mut n = Node {
            weight: weight,
            leaf_counts: Vec::with_capacity(capacity),
        };
        n.leaf_counts.push(initial_count);
        n
    }
}

#[derive(Debug)]
struct Leaf {
    weight: usize,
    index: usize,
}
impl PartialEq for Leaf {
    fn eq(&self, other: &Self) -> bool {
        self.weight == other.weight
    }
}
impl Eq for Leaf { }
impl Ord for Leaf {
    fn cmp(&self, other: &Self) -> Ordering {
        self.weight.cmp(&other.weight)
    }
}
impl PartialOrd for Leaf {
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

#[derive(Debug)]
struct List {
    lookahead1: Node,
    lookahead2: Node,
    next_leaf_index: usize,
}

/// Calculates the bitlengths for the Huffman tree, based on the counts of each
/// symbol.
pub fn length_limited_code_lengths(frequencies: &[usize], maxbits: i32) -> Vec<u32> {
    let mut leaves = vec![];

    // Count used symbols and place them in the leaves.
    for (i, &freq) in frequencies.iter().enumerate() {
        if freq != 0 {
            leaves.push(Leaf { weight: freq, index: i });
        }
    }

    // Short circuit some special cases
    if leaves.is_empty() {
        // There are no non-zero frequencies.
        return vec![0; frequencies.len()];
    }
    if leaves.len() == 1 {
        let mut result = vec![0; frequencies.len()];
        result[leaves[0].index] = 1;
        return result;
    }
    if leaves.len() == 2 {
        let mut result = vec![0; frequencies.len()];
        result[leaves[0].index] = 1;
        result[leaves[1].index] = 1;
        return result;
    }

    // Sort the leaves from least frequent to most frequent.
    // Add index into the same variable for stable sorting.
    for leaf in &mut leaves {
        leaf.weight = (leaf.weight << 9) | leaf.index;
    }
    leaves.sort();
    for leaf in &mut leaves {
        leaf.weight >>= 9;
    }

    let max_num_leaves = 2 * leaves.len() - 2;

    let mut lists = Vec::with_capacity(maxbits as usize);
    for _ in 0..maxbits {
        lists.push(List {
            lookahead1: Node::new(leaves[0].weight, 1, max_num_leaves),
            lookahead2: Node::new(leaves[1].weight, 2, max_num_leaves),
            next_leaf_index: 2,
        });
    }

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each boundary_pm run creates one.
    let num_boundary_pm_runs = max_num_leaves - 2;
    for _ in 0..num_boundary_pm_runs {
        boundary_pm_toplevel(&mut lists[..], &leaves);
    }

    let n = frequencies.len();
    let mut result = vec![0; n];

    let mut a = lists.pop().unwrap().lookahead2.leaf_counts.into_iter().rev().peekable();

    let mut bitlength_value = 1;
    while let Some(leaf_count) = a.next() {
        let next_count = *a.peek().unwrap_or(&0);
        for leaf in &leaves[next_count..leaf_count] {
            result[leaf.index] = bitlength_value;
        }
        bitlength_value += 1;
    }

    result
}

fn lowest_list(lists: &mut [List], leaves: &[Leaf]) {
    // We're in the lowest list, just add another leaf to the lookaheads
    // There will always be more leaves to be added on level 0 so this is safe.
    let mut current_list = lists.get_mut(0).unwrap();
    let next_leaf = &leaves[current_list.next_leaf_index];
    current_list.lookahead2.weight = next_leaf.weight;

    current_list.lookahead2.leaf_counts[0] = current_list.lookahead1.leaf_counts.last().unwrap() + 1;
    current_list.next_leaf_index += 1;
}

fn next_leaf(lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    let mut current_list = lists.get_mut(current_list_index).unwrap();

    // The next leaf goes next; counting itself makes the leaf_count increase by one.
    current_list.lookahead2.weight = leaves[current_list.next_leaf_index].weight;
    current_list.lookahead2.leaf_counts.clear();
    current_list.lookahead2.leaf_counts.extend_from_slice(&current_list.lookahead1.leaf_counts);
    let last_index = current_list.lookahead2.leaf_counts.len() - 1;
    current_list.lookahead2.leaf_counts[last_index] += 1;
    current_list.next_leaf_index += 1;
}

fn next_tree(weight_sum: usize, lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    {
        let (head, tail) = lists.split_at_mut(current_list_index);
        let prev_list = head.last_mut().unwrap();
        let current_list = tail.first_mut().unwrap();

        let previous_list_leaf_counts = &prev_list.lookahead2.leaf_counts;

        // Make a tree from the lookaheads from the previous list; that goes next.
        // This is not a leaf node, so the leaf count stays the same.
        current_list.lookahead2.weight = weight_sum;
        current_list.lookahead2.leaf_counts.clear();

        current_list.lookahead2.leaf_counts.extend_from_slice(previous_list_leaf_counts);
        current_list.lookahead2.leaf_counts.push(*current_list.lookahead1.leaf_counts.last().unwrap());
    }

    // The previous list needs two new lookahead nodes.
    boundary_pm(lists, leaves, current_list_index - 1);
    boundary_pm(lists, leaves, current_list_index - 1);
}

fn boundary_pm_toplevel(lists: &mut [List], leaves: &[Leaf]) {
    let last_index = lists.len() - 1;
    boundary_pm(lists, leaves, last_index);
}

fn boundary_pm(lists: &mut [List], leaves: &[Leaf], current_list_index: usize) {
    let next_leaf_index = lists[current_list_index].next_leaf_index;

    if current_list_index == 0 && next_leaf_index == leaves.len() {
        // We've added all the leaves to the lowest list, so we're done here
        return;
    }

    mem::swap(&mut lists[current_list_index].lookahead1, &mut lists[current_list_index].lookahead2);

    if current_list_index == 0 {
        lowest_list(lists, leaves);
    } else {
        // We're at a list other than the lowest list.
        let weight_sum = {
            let previous_list = lists.get(current_list_index - 1).unwrap();
            previous_list.lookahead1.weight + previous_list.lookahead2.weight
        };

        if next_leaf_index < leaves.len() && weight_sum > leaves[next_leaf_index].weight {
            next_leaf(lists, leaves, current_list_index);
        } else {
            next_tree(weight_sum, lists, leaves, current_list_index);
        }
    }
}

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

    #[test]
    fn test_from_paper_3() {
        let input = [1, 1, 5, 7, 10, 14];
        let output = length_limited_code_lengths(&input, 3);
        let answer = vec![3, 3, 3, 3, 2, 2];
        assert_eq!(output, answer);
    }

    #[test]
    fn test_from_paper_4() {
        let input = [1, 1, 5, 7, 10, 14];
        let output = length_limited_code_lengths(&input, 4);
        let answer = vec![4, 4, 3, 2, 2, 2];
        assert_eq!(output, answer);
    }

    #[test]
    fn maxbits_7() {
        let input = [252, 0, 1, 6, 9, 10, 6, 3, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![1, 0, 6, 4, 3, 3, 3, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn maxbits_15() {
        let input = [0, 0, 0, 0, 0, 0, 18, 0, 6, 0, 12, 2, 14, 9, 27, 15, 23, 15, 17, 8, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 15);
        let answer = vec! [0, 0, 0, 0, 0, 0, 3, 0, 5, 0, 4, 6, 4, 4, 3, 4, 3, 3, 3, 4, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn no_frequencies() {
        let input = [0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn only_one_frequency() {
        let input = [0, 10, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = vec![0, 1, 0];
        assert_eq!(output, answer);
    }

    #[test]
    fn only_two_frequencies() {
        let input = [0, 0, 0, 0, 252, 0, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        let output = length_limited_code_lengths(&input, 7);
        let answer = [0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
        assert_eq!(output, answer);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::response::ResponseHandler;
use dispatcher::Response;
use context::event::EventHandler;
use message::{Message, PatternId};
use reactor;

pub struct MessageEventHandler {
    handlers: HashMap<PatternId, Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>>,
    keyless_handlers: Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>,
    response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>,
}

impl MessageEventHandler {
    pub fn new(response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>) -> MessageEventHandler {
        MessageEventHandler{
            handlers: HashMap::new(),
            keyless_handlers: Vec::new(),
            response_handler: response_handler
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>) {
        let cloned_handler = handler.clone();
        if handler.borrow().handlers().is_empty() {
            self.keyless_handlers.push(cloned_handler);
        } else {
            for key in cloned_handler.borrow().handlers() {
                println!("key: {:?}", key);
                let handlers = self.handlers.entry(key.clone()).or_insert(Vec::new());
                handlers.push(cloned_handler.clone());
            }
        }
    }

    pub fn call_handlers_by_id(&mut self, id: &PatternId, event: Rc<Message>) {
        if let Some(handlers) = self.handlers.get_mut(id) {
            for i in handlers.iter_mut() {
                if let Some(result) = i.borrow_mut().handle_event(Request::Message(event.clone())) {
                    for i in result.into_iter() {
                        self.response_handler.borrow_mut().handle_response(i.into());
                    }
                }
            }
        }
    }
}

impl reactor::EventHandler<InternalRequest> for MessageEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
        if let Request::Message(event) = event {
            println!("message event");
            if let Some(id) = event.name() {
                self.call_handlers_by_id(id, event.clone());
            } else {
                let id = event.uuid();
                self.call_handlers_by_id(id, event.clone());
            }

            for i in self.keyless_handlers.iter_mut() {
                i.borrow_mut().handle_event(Request::Message(event.clone()));
            }
        } else {
            unreachable!("MessageEventHandler should only handle Message events");
        }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Message
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::cell::RefCell;
    use std::rc::Rc;

    use action::ExecResult;
    use context;
    use dispatcher::request::{InternalRequest, Request};
    use dispatcher::response::ResponseHandler;
    use dispatcher::Response;
    use message::{Builder, PatternId};
    use reactor::EventHandler;

    use super::MessageEventHandler;

    struct DummyResponseHandler(Rc<RefCell<i32>>);

    impl ResponseHandler<Response> for DummyResponseHandler {
        fn handle_response(&mut self, _: Response) {
            *self.0.borrow_mut() += 1;
        }
    }

    struct DummyEventHandler {
        counter: Rc<RefCell<i32>>,
        ids: Vec<PatternId>
    }

    impl context::event::EventHandler<InternalRequest> for DummyEventHandler {
        fn handle_event(&mut self, _: InternalRequest) -> Option<Vec<ExecResult>> {
            *self.counter.borrow_mut() += 1;
            None
        }
        fn handlers(&self) -> &[PatternId] {
            &self.ids
        }
    }

    #[test]
    fn test_given_message_event_handler_when_it_receives_a_message_then_it_calls_the_right_handler() {
        let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let response_handler_counter = Rc::new(RefCell::new(0));
        let response_handler: Box<ResponseHandler<Response>> = Box::new(DummyResponseHandler(response_handler_counter.clone()));
        let response_handler = Rc::new(RefCell::new(response_handler));
        let ids_1 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid1).unwrap()) ];
        let ids_2 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid2).unwrap()) ];
        let event_handler_counter_1 = Rc::new(RefCell::new(0));
        let event_handler_counter_2 = Rc::new(RefCell::new(0));
        let event_handler_1: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_1.clone(), ids: ids_1});
        let event_handler_2: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_2.clone(), ids: ids_2});
        let event_handler_1 = Rc::new(RefCell::new(event_handler_1));
        let event_handler_2 = Rc::new(RefCell::new(event_handler_2));
        let mut message_event_handler = MessageEventHandler::new(response_handler.clone());
        message_event_handler.register_handler(event_handler_1);
        message_event_handler.register_handler(event_handler_2);
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(1, *event_handler_counter_1.borrow());
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(2, *event_handler_counter_1.borrow());
        assert_eq!(0, *event_handler_counter_2.borrow());
        assert_eq!(0, *response_handler_counter.borrow());
    }
}
<commit_msg>MessageEventHandler: add a debug print<commit_after>use std::collections::HashMap;
use std::rc::Rc;
use std::cell::RefCell;

use context;
use dispatcher::request::{InternalRequest, Request, RequestHandler};
use dispatcher::response::ResponseHandler;
use dispatcher::Response;
use context::event::EventHandler;
use message::{Message, PatternId};
use reactor;

pub struct MessageEventHandler {
    handlers: HashMap<PatternId, Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>>,
    keyless_handlers: Vec<Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>>,
    response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>,
}

impl MessageEventHandler {
    pub fn new(response_handler: Rc<RefCell<Box<ResponseHandler<Response>>>>) -> MessageEventHandler {
        MessageEventHandler{
            handlers: HashMap::new(),
            keyless_handlers: Vec::new(),
            response_handler: response_handler
        }
    }

    pub fn register_handler(&mut self, handler: Rc<RefCell<Box<context::event::EventHandler<InternalRequest>>>>) {
        let cloned_handler = handler.clone();
        if handler.borrow().handlers().is_empty() {
            self.keyless_handlers.push(cloned_handler);
        } else {
            for key in cloned_handler.borrow().handlers() {
                println!("key: {:?}", key);
                let handlers = self.handlers.entry(key.clone()).or_insert(Vec::new());
                handlers.push(cloned_handler.clone());
            }
        }
    }

    pub fn call_handlers_by_id(&mut self, id: &PatternId, event: Rc<Message>) {
        if let Some(handlers) = self.handlers.get_mut(id) {
            for i in handlers.iter_mut() {
                if let Some(result) = i.borrow_mut().handle_event(Request::Message(event.clone())) {
                    for i in result.into_iter() {
                        self.response_handler.borrow_mut().handle_response(i.into());
                    }
                }
            }
        } else {
            println!("no handler found for id: {:?}", id);
        }
    }
}

impl reactor::EventHandler<InternalRequest> for MessageEventHandler {
    type Handler = RequestHandler;
    fn handle_event(&mut self, event: InternalRequest) {
        if let Request::Message(event) = event {
            println!("message event");
            if let Some(id) = event.name() {
                self.call_handlers_by_id(id, event.clone());
            } else {
                let id = event.uuid();
                self.call_handlers_by_id(id, event.clone());
            }

            for i in self.keyless_handlers.iter_mut() {
                i.borrow_mut().handle_event(Request::Message(event.clone()));
            }
        } else {
            unreachable!("MessageEventHandler should only handle Message events");
        }
    }
    fn handler(&self) -> Self::Handler {
        RequestHandler::Message
    }
}

#[cfg(test)]
mod test {
    use uuid::Uuid;
    use std::cell::RefCell;
    use std::rc::Rc;

    use action::ExecResult;
    use context;
    use dispatcher::request::{InternalRequest, Request};
    use dispatcher::response::ResponseHandler;
    use dispatcher::Response;
    use message::{Builder, PatternId};
    use reactor::EventHandler;

    use super::MessageEventHandler;

    struct DummyResponseHandler(Rc<RefCell<i32>>);

    impl ResponseHandler<Response> for DummyResponseHandler {
        fn handle_response(&mut self, _: Response) {
            *self.0.borrow_mut() += 1;
        }
    }

    struct DummyEventHandler {
        counter: Rc<RefCell<i32>>,
        ids: Vec<PatternId>
    }

    impl context::event::EventHandler<InternalRequest> for DummyEventHandler {
        fn handle_event(&mut self, _: InternalRequest) -> Option<Vec<ExecResult>> {
            *self.counter.borrow_mut() += 1;
            None
        }
        fn handlers(&self) -> &[PatternId] {
            &self.ids
        }
    }

    #[test]
    fn test_given_message_event_handler_when_it_receives_a_message_then_it_calls_the_right_handler() {
        let uuid1 = "1b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let uuid2 = "2b47ba91-d867-4a8c-9553-a5dfd6ea1274".to_string();
        let response_handler_counter = Rc::new(RefCell::new(0));
        let response_handler: Box<ResponseHandler<Response>> = Box::new(DummyResponseHandler(response_handler_counter.clone()));
        let response_handler = Rc::new(RefCell::new(response_handler));
        let ids_1 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid1).unwrap()) ];
        let ids_2 = vec![ PatternId::Uuid(Uuid::parse_str(&uuid2).unwrap()) ];
        let event_handler_counter_1 = Rc::new(RefCell::new(0));
        let event_handler_counter_2 = Rc::new(RefCell::new(0));
        let event_handler_1: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_1.clone(), ids: ids_1});
        let event_handler_2: Box<context::event::EventHandler<InternalRequest>> = Box::new(DummyEventHandler{counter: event_handler_counter_2.clone(), ids: ids_2});
        let event_handler_1 = Rc::new(RefCell::new(event_handler_1));
        let event_handler_2 = Rc::new(RefCell::new(event_handler_2));
        let mut message_event_handler = MessageEventHandler::new(response_handler.clone());
        message_event_handler.register_handler(event_handler_1);
        message_event_handler.register_handler(event_handler_2);
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(1, *event_handler_counter_1.borrow());
        message_event_handler.handle_event(Request::Message(Rc::new(Builder::new(&uuid1).build())));
        assert_eq!(2, *event_handler_counter_1.borrow());
        assert_eq!(0, *event_handler_counter_2.borrow());
        assert_eq!(0, *response_handler_counter.borrow());
    }
}
<|endoftext|>


<commit_before>use super::DocBuilder;
use db::file::add_path_into_database;
use db::{add_build_into_database, add_package_into_database, connect_db};
use docbuilder::{crates::crates_from_path, Limits};
use error::Result;
use failure::ResultExt;
use log::LevelFilter;
use postgres::Connection;
use rustc_serialize::json::ToJson;
use rustwide::cmd::{Command, SandboxBuilder};
use rustwide::logging::{self, LogStorage};
use rustwide::{Build, Crate, Toolchain, Workspace, WorkspaceBuilder};
use std::path::Path;
use utils::{copy_doc_dir, parse_rustc_version, CargoMetadata};
use Metadata;

static USER_AGENT: &str = "docs.rs builder (https://github.com/rust-lang/docs.rs)";
static DEFAULT_RUSTWIDE_WORKSPACE: &str = ".rustwide";

static TARGETS: &[&str] = &[
    "i686-apple-darwin",
    "i686-pc-windows-msvc",
    "i686-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-pc-windows-msvc",
    "x86_64-unknown-linux-gnu",
];
static DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";

static ESSENTIAL_FILES_VERSIONED: &[&str] = &[
    "brush.svg",
    "wheel.svg",
    "down-arrow.svg",
    "dark.css",
    "light.css",
    "main.js",
    "normalize.css",
    "rustdoc.css",
    "settings.css",
    "settings.js",
    "storage.js",
    "theme.js",
    "source-script.js",
    "noscript.css",
    "rust-logo.png",
];
static ESSENTIAL_FILES_UNVERSIONED: &[&str] = &[
    "FiraSans-Medium.woff",
    "FiraSans-Regular.woff",
    "SourceCodePro-Regular.woff",
    "SourceCodePro-Semibold.woff",
    "SourceSerifPro-Bold.ttf.woff",
    "SourceSerifPro-Regular.ttf.woff",
    "SourceSerifPro-It.ttf.woff",
];

static DUMMY_CRATE_NAME: &str = "acme-client";
static DUMMY_CRATE_VERSION: &str = "0.0.0";

pub struct RustwideBuilder {
    workspace: Workspace,
    toolchain: Toolchain,
    rustc_version: String,
}

impl RustwideBuilder {
    pub fn init() -> Result<Self> {
        let env_workspace_path = ::std::env::var("CRATESFYI_RUSTWIDE_WORKSPACE");
        let workspace_path = env_workspace_path
            .as_ref()
            .map(|v| v.as_str())
            .unwrap_or(DEFAULT_RUSTWIDE_WORKSPACE);
        let workspace = WorkspaceBuilder::new(Path::new(workspace_path), USER_AGENT).init()?;
        workspace.purge_all_build_dirs()?;

        let toolchain = Toolchain::Dist {
            name: "nightly".into(),
        };

        Ok(RustwideBuilder {
            workspace,
            toolchain,
            rustc_version: String::new(),
        })
    }

    fn update_toolchain(&mut self) -> Result<()> {
        // Ignore errors if detection fails.
        let old_version = self.detect_rustc_version().ok();

        self.toolchain.install(&self.workspace)?;
        for target in TARGETS {
            self.toolchain.add_target(&self.workspace, target)?;
        }
        self.rustc_version = self.detect_rustc_version()?;

        if old_version.as_ref().map(|s| s.as_str()) != Some(&self.rustc_version) {
            self.add_essential_files()?;
        }

        Ok(())
    }

    fn detect_rustc_version(&self) -> Result<String> {
        info!("detecting rustc's version...");
        let res = Command::new(&self.workspace, self.toolchain.rustc())
            .args(&["--version"])
            .log_output(false)
            .run_capture()?;
        let mut iter = res.stdout_lines().iter();
        if let (Some(line), None) = (iter.next(), iter.next()) {
            info!("found rustc {}", line);
            Ok(line.clone())
        } else {
            Err(::failure::err_msg(
                "invalid output returned by `rustc --version`",
            ))
        }
    }

    pub fn add_essential_files(&mut self) -> Result<()> {
        self.rustc_version = self.detect_rustc_version()?;
        let rustc_version = parse_rustc_version(&self.rustc_version)?;

        info!("building a dummy crate to get essential files");

        let conn = connect_db()?;
        let limits = Limits::for_crate(&conn, DUMMY_CRATE_NAME)?;

        let mut build_dir = self
            .workspace
            .build_dir(&format!("essential-files-{}", rustc_version));
        build_dir.purge()?;

        // acme-client-0.0.0 is an empty library crate and it will always build
        let krate = Crate::crates_io(DUMMY_CRATE_NAME, DUMMY_CRATE_VERSION);
        krate.fetch(&self.workspace)?;

        let sandbox = SandboxBuilder::new()
            .memory_limit(Some(limits.memory()))
            .enable_networking(limits.networking());

        build_dir
            .build(&self.toolchain, &krate, sandbox)
            .run(|build| {
                let res = self.execute_build(None, build, &limits)?;
                if !res.successful {
                    bail!("failed to build dummy crate for {}", self.rustc_version);
                }

                info!("copying essential files for {}", self.rustc_version);
                let source = build.host_target_dir().join(&res.target).join("doc");
                let dest = ::tempdir::TempDir::new("essential-files")?;

                let files = ESSENTIAL_FILES_VERSIONED
                    .iter()
                    .map(|f| (f, true))
                    .chain(ESSENTIAL_FILES_UNVERSIONED.iter().map(|f| (f, false)));
                for (file, versioned) in files {
                    let segments = file.rsplitn(2, '.').collect::<Vec<_>>();
                    let file_name = if versioned {
                        format!("{}-{}.{}", segments[1], rustc_version, segments[0])
                    } else {
                        file.to_string()
                    };
                    let source_path = source.join(&file_name);
                    let dest_path = dest.path().join(&file_name);
                    ::std::fs::copy(&source_path, &dest_path).with_context(|_| {
                        format!(
                            "couldn't copy '{}' to '{}'",
                            source_path.display(),
                            dest_path.display()
                        )
                    })?;
                }

                add_path_into_database(&conn, "", &dest)?;
                conn.query(
                    "INSERT INTO config (name, value) VALUES ('rustc_version', $1) \
                     ON CONFLICT (name) DO UPDATE SET value = $1;",
                    &[&self.rustc_version.to_json()],
                )?;

                Ok(())
            })?;

        build_dir.purge()?;
        krate.purge_from_cache(&self.workspace)?;
        Ok(())
    }

    pub fn build_world(&mut self, doc_builder: &mut DocBuilder) -> Result<()> {
        let mut count = 0;
        crates_from_path(
            &doc_builder.options().crates_io_index_path.clone(),
            &mut |name, version| {
                match self.build_package(doc_builder, name, version) {
                    Ok(status) => {
                        count += 1;
                        if status && count % 10 == 0 {
                            let _ = doc_builder.save_cache();
                        }
                    }
                    Err(err) => warn!("failed to build package {} {}: {}", name, version, err),
                }
                doc_builder.add_to_cache(name, version);
            },
        )
    }

    pub fn build_package(
        &mut self,
        doc_builder: &mut DocBuilder,
        name: &str,
        version: &str,
    ) -> Result<bool> {
        if !doc_builder.should_build(name, version) {
            return Ok(false);
        }

        self.update_toolchain()?;

        info!("building package {} {}", name, version);

        let conn = connect_db()?;
        let limits = Limits::for_crate(&conn, name)?;

        let mut build_dir = self.workspace.build_dir(&format!("{}-{}", name, version));
        build_dir.purge()?;

        let krate = Crate::crates_io(name, version);
        krate.fetch(&self.workspace)?;

        let sandbox = SandboxBuilder::new()
            .memory_limit(Some(limits.memory()))
            .enable_networking(limits.networking());

        let res = build_dir
            .build(&self.toolchain, &krate, sandbox)
            .run(|build| {
                let mut files_list = None;
                let mut has_docs = false;
                let mut successful_targets = Vec::new();

                // Do an initial build and then copy the sources in the database
                let res = self.execute_build(None, &build, &limits)?;
                if res.successful {
                    debug!("adding sources into database");
                    let prefix = format!("sources/{}/{}", name, version);
                    files_list = Some(add_path_into_database(
                        &conn,
                        &prefix,
                        build.host_source_dir(),
                    )?);

                    has_docs = build
                        .host_target_dir()
                        .join(&res.target)
                        .join("doc")
                        .join(name.replace("-", "_"))
                        .is_dir();
                }

                if has_docs {
                    debug!("adding documentation for the default target to the database");
                    self.copy_docs(
                        &doc_builder,
                        &build.host_target_dir(),
                        name,
                        version,
                        &res.target,
                        true,
                    )?;

                    // Then build the documentation for all the targets
                    for target in TARGETS {
                        debug!("building package {} {} for {}", name, version, target);
                        let target_res = self.execute_build(Some(target), &build, &limits)?;
                        if target_res.successful {
                            // Cargo is not giving any error and not generating documentation of some crates
                            // when we use a target compile options. Check documentation exists before
                            // adding target to successfully_targets.
                            if build.host_target_dir().join(target).join("doc").is_dir() {
                                debug!(
                                    "adding documentation for target {} to the database",
                                    target
                                );
                                self.copy_docs(
                                    &doc_builder,
                                    &build.host_target_dir(),
                                    name,
                                    version,
                                    target,
                                    false,
                                )?;
                                successful_targets.push(target.to_string());
                            }
                        }
                    }

                    self.upload_docs(doc_builder, &conn, name, version)?;
                }

                let has_examples = build.host_source_dir().join("examples").is_dir();
                let release_id = add_package_into_database(
                    &conn,
                    res.cargo_metadata.root(),
                    &build.host_source_dir(),
                    &res,
                    files_list,
                    successful_targets,
                    has_docs,
                    has_examples,
                )?;
                add_build_into_database(&conn, &release_id, &res)?;

                doc_builder.add_to_cache(name, version);
                Ok(res)
            })?;

        build_dir.purge()?;
        krate.purge_from_cache(&self.workspace)?;
        Ok(res.successful)
    }

    fn execute_build(
        &self,
        target: Option<&str>,
        build: &Build,
        limits: &Limits,
    ) -> Result<BuildResult> {
        let metadata = Metadata::from_source_dir(&build.host_source_dir())?;
        let cargo_metadata =
            CargoMetadata::load(&self.workspace, &self.toolchain, &build.host_source_dir())?;

        let target = if let Some(target) = target {
            target
        } else if let Some(target) = metadata.default_target.as_ref().map(|s| s.as_str()) {
            target
        } else {
            DEFAULT_TARGET
        }
        .to_string();

        let mut rustdoc_flags: Vec<String> = vec![
            "-Z".to_string(),
            "unstable-options".to_string(),
            "--resource-suffix".to_string(),
            format!("-{}", parse_rustc_version(&self.rustc_version)?),
            "--static-root-path".to_string(),
            "/".to_string(),
            "--disable-per-crate-search".to_string(),
        ];
        for dep in &cargo_metadata.root_dependencies() {
            rustdoc_flags.push("--extern-html-root-url".to_string());
            rustdoc_flags.push(format!(
                "{}=https://docs.rs/{}/{}",
                dep.name.replace("-", "_"),
                dep.name,
                dep.version
            ));
        }
        let mut cargo_args = vec![
            "doc".to_owned(),
            "--lib".to_owned(),
            "--no-deps".to_owned(),
            "--target".to_owned(),
            target.to_owned(),
        ];
        if let Some(features) = &metadata.features {
            cargo_args.push("--features".to_owned());
            cargo_args.push(features.join(" "));
        }
        if metadata.all_features {
            cargo_args.push("--all-features".to_owned());
        }
        if metadata.no_default_features {
            cargo_args.push("--no-default-features".to_owned());
        }

        let mut storage = LogStorage::new(LevelFilter::Info);
        storage.set_max_size(limits.max_log_size());

        let successful = logging::capture(&storage, || {
            build
                .cargo()
                .timeout(Some(limits.timeout()))
                .no_output_timeout(None)
                .env(
                    "RUSTFLAGS",
                    metadata
                        .rustc_args
                        .map(|args| args.join(""))
                        .unwrap_or("".to_owned()),
                )
                .env("RUSTDOCFLAGS", rustdoc_flags.join(" "))
                .args(&cargo_args)
                .run()
                .is_ok()
        });

        Ok(BuildResult {
            build_log: storage.to_string(),
            rustc_version: self.rustc_version.clone(),
            docsrs_version: format!("docsrs {}", ::BUILD_VERSION),
            successful,
            cargo_metadata,
            target: target.to_string(),
        })
    }

    fn copy_docs(
        &self,
        doc_builder: &DocBuilder,
        target_dir: &Path,
        name: &str,
        version: &str,
        target: &str,
        is_default_target: bool,
    ) -> Result<()> {
        let source = target_dir.join(target);

        let mut dest = doc_builder.options().destination.join(name).join(version);
        // only add target name to destination directory when we are copying a non-default target.
        // this is allowing us to host documents in the root of the crate documentation directory.
        // for example winapi will be available in docs.rs/winapi/$version/winapi/ for it's
        // default target: x86_64-pc-windows-msvc. But since it will be built under
        // cratesfyi/x86_64-pc-windows-msvc we still need target in this function.
        if !is_default_target {
            dest = dest.join(target);
        }

        info!("{} {}", source.display(), dest.display());
        copy_doc_dir(source, dest, self.rustc_version.trim())?;
        Ok(())
    }

    fn upload_docs(
        &self,
        doc_builder: &DocBuilder,
        conn: &Connection,
        name: &str,
        version: &str,
    ) -> Result<()> {
        debug!("Adding documentation into database");
        let prefix = format!("rustdoc/{}/{}", name, version);
        let database_prefix =
            Path::new(&doc_builder.options().destination).join(format!("{}/{}", name, version));
        add_path_into_database(conn, &prefix, database_prefix)?;
        Ok(())
    }
}

pub(crate) struct BuildResult {
    pub(crate) rustc_version: String,
    pub(crate) docsrs_version: String,
    pub(crate) build_log: String,
    pub(crate) successful: bool,
    target: String,
    cargo_metadata: CargoMetadata,
}
<commit_msg>allow pinning the rust toolchain version manually<commit_after>use super::DocBuilder;
use db::file::add_path_into_database;
use db::{add_build_into_database, add_package_into_database, connect_db};
use docbuilder::{crates::crates_from_path, Limits};
use error::Result;
use failure::ResultExt;
use log::LevelFilter;
use postgres::Connection;
use rustc_serialize::json::ToJson;
use rustwide::cmd::{Command, SandboxBuilder};
use rustwide::logging::{self, LogStorage};
use rustwide::{Build, Crate, Toolchain, Workspace, WorkspaceBuilder};
use std::borrow::Cow;
use std::path::Path;
use utils::{copy_doc_dir, parse_rustc_version, CargoMetadata};
use Metadata;

static USER_AGENT: &str = "docs.rs builder (https://github.com/rust-lang/docs.rs)";
static DEFAULT_RUSTWIDE_WORKSPACE: &str = ".rustwide";

static TARGETS: &[&str] = &[
    "i686-apple-darwin",
    "i686-pc-windows-msvc",
    "i686-unknown-linux-gnu",
    "x86_64-apple-darwin",
    "x86_64-pc-windows-msvc",
    "x86_64-unknown-linux-gnu",
];
static DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu";

static ESSENTIAL_FILES_VERSIONED: &[&str] = &[
    "brush.svg",
    "wheel.svg",
    "down-arrow.svg",
    "dark.css",
    "light.css",
    "main.js",
    "normalize.css",
    "rustdoc.css",
    "settings.css",
    "settings.js",
    "storage.js",
    "theme.js",
    "source-script.js",
    "noscript.css",
    "rust-logo.png",
];
static ESSENTIAL_FILES_UNVERSIONED: &[&str] = &[
    "FiraSans-Medium.woff",
    "FiraSans-Regular.woff",
    "SourceCodePro-Regular.woff",
    "SourceCodePro-Semibold.woff",
    "SourceSerifPro-Bold.ttf.woff",
    "SourceSerifPro-Regular.ttf.woff",
    "SourceSerifPro-It.ttf.woff",
];

static DUMMY_CRATE_NAME: &str = "acme-client";
static DUMMY_CRATE_VERSION: &str = "0.0.0";

pub struct RustwideBuilder {
    workspace: Workspace,
    toolchain: Toolchain,
    rustc_version: String,
}

impl RustwideBuilder {
    pub fn init() -> Result<Self> {
        let env_workspace_path = ::std::env::var("CRATESFYI_RUSTWIDE_WORKSPACE");
        let workspace_path = env_workspace_path
            .as_ref()
            .map(|v| v.as_str())
            .unwrap_or(DEFAULT_RUSTWIDE_WORKSPACE);
        let workspace = WorkspaceBuilder::new(Path::new(workspace_path), USER_AGENT).init()?;
        workspace.purge_all_build_dirs()?;

        let toolchain_name = std::env::var("CRATESFYI_TOOLCHAIN")
            .map(|t| Cow::Owned(t))
            .unwrap_or_else(|_| Cow::Borrowed("nightly"));

        let toolchain = Toolchain::Dist {
            name: toolchain_name,
        };

        Ok(RustwideBuilder {
            workspace,
            toolchain,
            rustc_version: String::new(),
        })
    }

    fn update_toolchain(&mut self) -> Result<()> {
        // Ignore errors if detection fails.
        let old_version = self.detect_rustc_version().ok();

        self.toolchain.install(&self.workspace)?;
        for target in TARGETS {
            self.toolchain.add_target(&self.workspace, target)?;
        }
        self.rustc_version = self.detect_rustc_version()?;

        if old_version.as_ref().map(|s| s.as_str()) != Some(&self.rustc_version) {
            self.add_essential_files()?;
        }

        Ok(())
    }

    fn detect_rustc_version(&self) -> Result<String> {
        info!("detecting rustc's version...");
        let res = Command::new(&self.workspace, self.toolchain.rustc())
            .args(&["--version"])
            .log_output(false)
            .run_capture()?;
        let mut iter = res.stdout_lines().iter();
        if let (Some(line), None) = (iter.next(), iter.next()) {
            info!("found rustc {}", line);
            Ok(line.clone())
        } else {
            Err(::failure::err_msg(
                "invalid output returned by `rustc --version`",
            ))
        }
    }

    pub fn add_essential_files(&mut self) -> Result<()> {
        self.rustc_version = self.detect_rustc_version()?;
        let rustc_version = parse_rustc_version(&self.rustc_version)?;

        info!("building a dummy crate to get essential files");

        let conn = connect_db()?;
        let limits = Limits::for_crate(&conn, DUMMY_CRATE_NAME)?;

        let mut build_dir = self
            .workspace
            .build_dir(&format!("essential-files-{}", rustc_version));
        build_dir.purge()?;

        // acme-client-0.0.0 is an empty library crate and it will always build
        let krate = Crate::crates_io(DUMMY_CRATE_NAME, DUMMY_CRATE_VERSION);
        krate.fetch(&self.workspace)?;

        let sandbox = SandboxBuilder::new()
            .memory_limit(Some(limits.memory()))
            .enable_networking(limits.networking());

        build_dir
            .build(&self.toolchain, &krate, sandbox)
            .run(|build| {
                let res = self.execute_build(None, build, &limits)?;
                if !res.successful {
                    bail!("failed to build dummy crate for {}", self.rustc_version);
                }

                info!("copying essential files for {}", self.rustc_version);
                let source = build.host_target_dir().join(&res.target).join("doc");
                let dest = ::tempdir::TempDir::new("essential-files")?;

                let files = ESSENTIAL_FILES_VERSIONED
                    .iter()
                    .map(|f| (f, true))
                    .chain(ESSENTIAL_FILES_UNVERSIONED.iter().map(|f| (f, false)));
                for (file, versioned) in files {
                    let segments = file.rsplitn(2, '.').collect::<Vec<_>>();
                    let file_name = if versioned {
                        format!("{}-{}.{}", segments[1], rustc_version, segments[0])
                    } else {
                        file.to_string()
                    };
                    let source_path = source.join(&file_name);
                    let dest_path = dest.path().join(&file_name);
                    ::std::fs::copy(&source_path, &dest_path).with_context(|_| {
                        format!(
                            "couldn't copy '{}' to '{}'",
                            source_path.display(),
                            dest_path.display()
                        )
                    })?;
                }

                add_path_into_database(&conn, "", &dest)?;
                conn.query(
                    "INSERT INTO config (name, value) VALUES ('rustc_version', $1) \
                     ON CONFLICT (name) DO UPDATE SET value = $1;",
                    &[&self.rustc_version.to_json()],
                )?;

                Ok(())
            })?;

        build_dir.purge()?;
        krate.purge_from_cache(&self.workspace)?;
        Ok(())
    }

    pub fn build_world(&mut self, doc_builder: &mut DocBuilder) -> Result<()> {
        let mut count = 0;
        crates_from_path(
            &doc_builder.options().crates_io_index_path.clone(),
            &mut |name, version| {
                match self.build_package(doc_builder, name, version) {
                    Ok(status) => {
                        count += 1;
                        if status && count % 10 == 0 {
                            let _ = doc_builder.save_cache();
                        }
                    }
                    Err(err) => warn!("failed to build package {} {}: {}", name, version, err),
                }
                doc_builder.add_to_cache(name, version);
            },
        )
    }

    pub fn build_package(
        &mut self,
        doc_builder: &mut DocBuilder,
        name: &str,
        version: &str,
    ) -> Result<bool> {
        if !doc_builder.should_build(name, version) {
            return Ok(false);
        }

        self.update_toolchain()?;

        info!("building package {} {}", name, version);

        let conn = connect_db()?;
        let limits = Limits::for_crate(&conn, name)?;

        let mut build_dir = self.workspace.build_dir(&format!("{}-{}", name, version));
        build_dir.purge()?;

        let krate = Crate::crates_io(name, version);
        krate.fetch(&self.workspace)?;

        let sandbox = SandboxBuilder::new()
            .memory_limit(Some(limits.memory()))
            .enable_networking(limits.networking());

        let res = build_dir
            .build(&self.toolchain, &krate, sandbox)
            .run(|build| {
                let mut files_list = None;
                let mut has_docs = false;
                let mut successful_targets = Vec::new();

                // Do an initial build and then copy the sources in the database
                let res = self.execute_build(None, &build, &limits)?;
                if res.successful {
                    debug!("adding sources into database");
                    let prefix = format!("sources/{}/{}", name, version);
                    files_list = Some(add_path_into_database(
                        &conn,
                        &prefix,
                        build.host_source_dir(),
                    )?);

                    has_docs = build
                        .host_target_dir()
                        .join(&res.target)
                        .join("doc")
                        .join(name.replace("-", "_"))
                        .is_dir();
                }

                if has_docs {
                    debug!("adding documentation for the default target to the database");
                    self.copy_docs(
                        &doc_builder,
                        &build.host_target_dir(),
                        name,
                        version,
                        &res.target,
                        true,
                    )?;

                    // Then build the documentation for all the targets
                    for target in TARGETS {
                        debug!("building package {} {} for {}", name, version, target);
                        let target_res = self.execute_build(Some(target), &build, &limits)?;
                        if target_res.successful {
                            // Cargo is not giving any error and not generating documentation of some crates
                            // when we use a target compile options. Check documentation exists before
                            // adding target to successfully_targets.
                            if build.host_target_dir().join(target).join("doc").is_dir() {
                                debug!(
                                    "adding documentation for target {} to the database",
                                    target
                                );
                                self.copy_docs(
                                    &doc_builder,
                                    &build.host_target_dir(),
                                    name,
                                    version,
                                    target,
                                    false,
                                )?;
                                successful_targets.push(target.to_string());
                            }
                        }
                    }

                    self.upload_docs(doc_builder, &conn, name, version)?;
                }

                let has_examples = build.host_source_dir().join("examples").is_dir();
                let release_id = add_package_into_database(
                    &conn,
                    res.cargo_metadata.root(),
                    &build.host_source_dir(),
                    &res,
                    files_list,
                    successful_targets,
                    has_docs,
                    has_examples,
                )?;
                add_build_into_database(&conn, &release_id, &res)?;

                doc_builder.add_to_cache(name, version);
                Ok(res)
            })?;

        build_dir.purge()?;
        krate.purge_from_cache(&self.workspace)?;
        Ok(res.successful)
    }

    fn execute_build(
        &self,
        target: Option<&str>,
        build: &Build,
        limits: &Limits,
    ) -> Result<BuildResult> {
        let metadata = Metadata::from_source_dir(&build.host_source_dir())?;
        let cargo_metadata =
            CargoMetadata::load(&self.workspace, &self.toolchain, &build.host_source_dir())?;

        let target = if let Some(target) = target {
            target
        } else if let Some(target) = metadata.default_target.as_ref().map(|s| s.as_str()) {
            target
        } else {
            DEFAULT_TARGET
        }
        .to_string();

        let mut rustdoc_flags: Vec<String> = vec![
            "-Z".to_string(),
            "unstable-options".to_string(),
            "--resource-suffix".to_string(),
            format!("-{}", parse_rustc_version(&self.rustc_version)?),
            "--static-root-path".to_string(),
            "/".to_string(),
            "--disable-per-crate-search".to_string(),
        ];
        for dep in &cargo_metadata.root_dependencies() {
            rustdoc_flags.push("--extern-html-root-url".to_string());
            rustdoc_flags.push(format!(
                "{}=https://docs.rs/{}/{}",
                dep.name.replace("-", "_"),
                dep.name,
                dep.version
            ));
        }
        let mut cargo_args = vec![
            "doc".to_owned(),
            "--lib".to_owned(),
            "--no-deps".to_owned(),
            "--target".to_owned(),
            target.to_owned(),
        ];
        if let Some(features) = &metadata.features {
            cargo_args.push("--features".to_owned());
            cargo_args.push(features.join(" "));
        }
        if metadata.all_features {
            cargo_args.push("--all-features".to_owned());
        }
        if metadata.no_default_features {
            cargo_args.push("--no-default-features".to_owned());
        }

        let mut storage = LogStorage::new(LevelFilter::Info);
        storage.set_max_size(limits.max_log_size());

        let successful = logging::capture(&storage, || {
            build
                .cargo()
                .timeout(Some(limits.timeout()))
                .no_output_timeout(None)
                .env(
                    "RUSTFLAGS",
                    metadata
                        .rustc_args
                        .map(|args| args.join(""))
                        .unwrap_or("".to_owned()),
                )
                .env("RUSTDOCFLAGS", rustdoc_flags.join(" "))
                .args(&cargo_args)
                .run()
                .is_ok()
        });

        Ok(BuildResult {
            build_log: storage.to_string(),
            rustc_version: self.rustc_version.clone(),
            docsrs_version: format!("docsrs {}", ::BUILD_VERSION),
            successful,
            cargo_metadata,
            target: target.to_string(),
        })
    }

    fn copy_docs(
        &self,
        doc_builder: &DocBuilder,
        target_dir: &Path,
        name: &str,
        version: &str,
        target: &str,
        is_default_target: bool,
    ) -> Result<()> {
        let source = target_dir.join(target);

        let mut dest = doc_builder.options().destination.join(name).join(version);
        // only add target name to destination directory when we are copying a non-default target.
        // this is allowing us to host documents in the root of the crate documentation directory.
        // for example winapi will be available in docs.rs/winapi/$version/winapi/ for it's
        // default target: x86_64-pc-windows-msvc. But since it will be built under
        // cratesfyi/x86_64-pc-windows-msvc we still need target in this function.
        if !is_default_target {
            dest = dest.join(target);
        }

        info!("{} {}", source.display(), dest.display());
        copy_doc_dir(source, dest, self.rustc_version.trim())?;
        Ok(())
    }

    fn upload_docs(
        &self,
        doc_builder: &DocBuilder,
        conn: &Connection,
        name: &str,
        version: &str,
    ) -> Result<()> {
        debug!("Adding documentation into database");
        let prefix = format!("rustdoc/{}/{}", name, version);
        let database_prefix =
            Path::new(&doc_builder.options().destination).join(format!("{}/{}", name, version));
        add_path_into_database(conn, &prefix, database_prefix)?;
        Ok(())
    }
}

pub(crate) struct BuildResult {
    pub(crate) rustc_version: String,
    pub(crate) docsrs_version: String,
    pub(crate) build_log: String,
    pub(crate) successful: bool,
    target: String,
    cargo_metadata: CargoMetadata,
}
<|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.

//! # The Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`strbuf`](strbuf/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UPD, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_id = "std#0.11.0-pre"]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]
#![feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args,
           linkage, default_type_params, phase, concat_idents, quad_precision_float)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] #[phase(syntax, link)] extern crate log;

// Make and rand accessible for benchmarking/testcases
#[cfg(test)] extern crate rand;

extern crate alloc;
extern crate core;
extern crate libc;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate realstd = "std";
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::char;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::container;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
#[cfg(not(test))] pub use core::ty;
pub use core::result;

pub use alloc::owned;
pub use alloc::rc;

// Run tests with libgreen instead of libnative.
//
// FIXME: This egregiously hacks around starting the test runner in a different
//        threading mode than the default by reaching into the auto-generated
//        '__test' module.
#[cfg(test)] #[start]
fn start(argc: int, argv: **u8) -> int {
    green::start(argc, argv, rustuv::event_loop, __test::main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod slice;
pub mod vec;
pub mod str;
pub mod string;

pub mod ascii;

pub mod gc;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_str;
pub mod hash;

/* Common data structures */

pub mod option;

/* Tasks and communication */

pub mod task;
pub mod comm;
pub mod local_data;
pub mod sync;

/* Runtime and platform support */

pub mod c_str;
pub mod c_vec;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;
pub mod cleanup;

/* Unsupported interfaces */

#[unstable]
pub mod repr;
#[unstable]
pub mod reflect;

// Private APIs
#[unstable]
pub mod unstable;

/* For internal use, not exported */

mod unicode;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
#[unstable]
pub mod rt;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!()
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use os = realstd::os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;
}
<commit_msg>doc: Fix link to string<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.

//! # The Rust Standard Library
//!
//! The Rust Standard Library provides the essential runtime
//! functionality for building portable Rust software.
//! It is linked to all Rust crates by default.
//!
//! ## Intrinsic types and operations
//!
//! The [`ptr`](ptr/index.html) and [`mem`](mem/index.html)
//! modules deal with unsafe pointers and memory manipulation.
//! [`kinds`](kinds/index.html) defines the special built-in traits,
//! and [`raw`](raw/index.html) the runtime representation of Rust types.
//! These are some of the lowest-level building blocks in Rust.
//!
//! ## Math on primitive types and math traits
//!
//! Although basic operations on primitive types are implemented
//! directly by the compiler, the standard library additionally
//! defines many common operations through traits defined in
//! mod [`num`](num/index.html).
//!
//! ## Pervasive types
//!
//! The [`option`](option/index.html) and [`result`](result/index.html)
//! modules define optional and error-handling types, `Option` and `Result`.
//! [`iter`](iter/index.html) defines Rust's iterator protocol
//! along with a wide variety of iterators.
//! [`Cell` and `RefCell`](cell/index.html) are for creating types that
//! manage their own mutability.
//!
//! ## Vectors, slices and strings
//!
//! The common container type, `Vec`, a growable vector backed by an
//! array, lives in the [`vec`](vec/index.html) module. References to
//! arrays, `&[T]`, more commonly called "slices", are built-in types
//! for which the [`slice`](slice/index.html) module defines many
//! methods.
//!
//! `&str`, a UTF-8 string, is a built-in type, and the standard library
//! defines methods for it on a variety of traits in the
//! [`str`](str/index.html) module. Rust strings are immutable;
//! use the `String` type defined in [`string`](string/index.html)
//! for a mutable string builder.
//!
//! For converting to strings use the [`format!`](fmt/index.html)
//! macro, and for converting from strings use the
//! [`FromStr`](from_str/index.html) trait.
//!
//! ## Platform abstractions
//!
//! Besides basic data types, the standard library is largely concerned
//! with abstracting over differences in common platforms, most notably
//! Windows and Unix derivatives. The [`os`](os/index.html) module
//! provides a number of basic functions for interacting with the
//! operating environment, including program arguments, environment
//! variables, and directory navigation. The [`path`](path/index.html)
//! module encapsulates the platform-specific rules for dealing
//! with file paths.
//!
//! `std` also includes modules for interoperating with the
//! C language: [`c_str`](c_str/index.html) and
//! [`c_vec`](c_vec/index.html).
//!
//! ## Concurrency, I/O, and the runtime
//!
//! The [`task`](task/index.html) module contains Rust's threading abstractions,
//! while [`comm`](comm/index.html) contains the channel types for message
//! passing. [`sync`](sync/index.html) contains further, primitive, shared
//! memory types, including [`atomics`](sync/atomics/index.html).
//!
//! Common types of I/O, including files, TCP, UPD, pipes, Unix domain sockets,
//! timers, and process spawning, are defined in the [`io`](io/index.html) module.
//!
//! Rust's I/O and concurrency depends on a small runtime interface
//! that lives, along with its support code, in mod [`rt`](rt/index.html).
//! While a notable part of the standard library's architecture, this
//! module is not intended for public use.
//!
//! ## The Rust prelude and macros
//!
//! Finally, the [`prelude`](prelude/index.html) defines a
//! common set of traits, types, and functions that are made available
//! to all code by default. [`macros`](macros/index.html) contains
//! all the standard macros, such as `assert!`, `fail!`, `println!`,
//! and `format!`, also available to all Rust code.

#![crate_id = "std#0.11.0-pre"]
#![comment = "The Rust standard library"]
#![license = "MIT/ASL2"]
#![crate_type = "rlib"]
#![crate_type = "dylib"]
#![doc(html_logo_url = "http://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png",
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/")]
#![feature(macro_rules, globs, asm, managed_boxes, thread_local, link_args,
           linkage, default_type_params, phase, concat_idents, quad_precision_float)]

// Don't link to std. We are std.
#![no_std]

#![allow(deprecated)]
#![deny(missing_doc)]

// When testing libstd, bring in libuv as the I/O backend so tests can print
// things and all of the std::io tests have an I/O interface to run on top
// of
#[cfg(test)] extern crate rustuv;
#[cfg(test)] extern crate native;
#[cfg(test)] extern crate green;
#[cfg(test)] #[phase(syntax, link)] extern crate log;

// Make and rand accessible for benchmarking/testcases
#[cfg(test)] extern crate rand;

extern crate alloc;
extern crate core;
extern crate libc;

// Make std testable by not duplicating lang items. See #2912
#[cfg(test)] extern crate realstd = "std";
#[cfg(test)] pub use realstd::kinds;
#[cfg(test)] pub use realstd::ops;
#[cfg(test)] pub use realstd::cmp;
#[cfg(test)] pub use realstd::ty;

// NB: These reexports are in the order they should be listed in rustdoc

pub use core::any;
pub use core::bool;
pub use core::cell;
pub use core::char;
pub use core::clone;
#[cfg(not(test))] pub use core::cmp;
pub use core::container;
pub use core::default;
pub use core::finally;
pub use core::intrinsics;
pub use core::iter;
#[cfg(not(test))] pub use core::kinds;
pub use core::mem;
#[cfg(not(test))] pub use core::ops;
pub use core::ptr;
pub use core::raw;
pub use core::simd;
pub use core::tuple;
#[cfg(not(test))] pub use core::ty;
pub use core::result;

pub use alloc::owned;
pub use alloc::rc;

// Run tests with libgreen instead of libnative.
//
// FIXME: This egregiously hacks around starting the test runner in a different
//        threading mode than the default by reaching into the auto-generated
//        '__test' module.
#[cfg(test)] #[start]
fn start(argc: int, argv: **u8) -> int {
    green::start(argc, argv, rustuv::event_loop, __test::main)
}

/* Exported macros */

pub mod macros;
pub mod bitflags;

mod rtdeps;

/* The Prelude. */

pub mod prelude;

/* Primitive types */

#[path = "num/float_macros.rs"] mod float_macros;
#[path = "num/int_macros.rs"]   mod int_macros;
#[path = "num/uint_macros.rs"]  mod uint_macros;

#[path = "num/int.rs"]  pub mod int;
#[path = "num/i8.rs"]   pub mod i8;
#[path = "num/i16.rs"]  pub mod i16;
#[path = "num/i32.rs"]  pub mod i32;
#[path = "num/i64.rs"]  pub mod i64;

#[path = "num/uint.rs"] pub mod uint;
#[path = "num/u8.rs"]   pub mod u8;
#[path = "num/u16.rs"]  pub mod u16;
#[path = "num/u32.rs"]  pub mod u32;
#[path = "num/u64.rs"]  pub mod u64;

#[path = "num/f32.rs"]   pub mod f32;
#[path = "num/f64.rs"]   pub mod f64;

pub mod slice;
pub mod vec;
pub mod str;
pub mod string;

pub mod ascii;

pub mod gc;

/* Common traits */

pub mod from_str;
pub mod num;
pub mod to_str;
pub mod hash;

/* Common data structures */

pub mod option;

/* Tasks and communication */

pub mod task;
pub mod comm;
pub mod local_data;
pub mod sync;

/* Runtime and platform support */

pub mod c_str;
pub mod c_vec;
pub mod os;
pub mod io;
pub mod path;
pub mod fmt;
pub mod cleanup;

/* Unsupported interfaces */

#[unstable]
pub mod repr;
#[unstable]
pub mod reflect;

// Private APIs
#[unstable]
pub mod unstable;

/* For internal use, not exported */

mod unicode;

// FIXME #7809: This shouldn't be pub, and it should be reexported under 'unstable'
// but name resolution doesn't work without it being pub.
#[unstable]
pub mod rt;

// A curious inner-module that's not exported that contains the binding
// 'std' so that macro-expanded references to std::error and such
// can be resolved within libstd.
#[doc(hidden)]
mod std {
    // mods used for deriving
    pub use clone;
    pub use cmp;
    pub use hash;

    pub use comm; // used for select!()
    pub use fmt; // used for any formatting strings
    pub use io; // used for println!()
    pub use local_data; // used for local_data_key!()
    pub use option; // used for bitflags!()
    pub use rt; // used for fail!()
    pub use vec; // used for vec![]

    // The test runner calls ::std::os::args() but really wants realstd
    #[cfg(test)] pub use os = realstd::os;
    // The test runner requires std::slice::Vector, so re-export std::slice just for it.
    #[cfg(test)] pub use slice;
}
<|endoftext|>


<commit_before>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use sys;
use ::{Instance, Media, EventManager};

pub struct MediaList {
    pub(crate) ptr: *mut sys::libvlc_media_list_t,
}

impl MediaList {
    /// Create an empty media list.
    pub fn new(instance: &Instance) -> Option<MediaList> {
        unsafe{
            let p = sys::libvlc_media_list_new(instance.ptr);
            if p.is_null() { None }else{ Some(MediaList{ptr: p}) }
        }
    }

    /// Associate media instance with this media list instance.
    /// If another media instance was present it will be released. The libvlc_media_list_lock should NOT be held upon entering this function.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_list_set_media(self.ptr, md.ptr); }
    }

    /// Get media instance from this media list instance.
    /// The MediaList::lock should NOT be held upon entering this function.
    pub fn media(&self) -> Option<Media> {
        unsafe{
            let p = sys::libvlc_media_list_media(self.ptr);
            if p.is_null() { None }else{ Some(Media{ptr: p}) }
        }
    }

    /// Add media instance to media list.
    /// The MediaList::lock should be held upon entering this function.
    pub fn add_media(&self, md: &Media) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_add_media(self.ptr, md.ptr) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Insert media instance in media list on a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn insert_media(&self, md: &Media, pos: i32) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_insert_media(self.ptr, md.ptr, pos) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Remove media instance from media list on a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn remove_index(&self, pos: i32) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_remove_index(self.ptr, pos) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Get count on media list items.
    /// The MediaList::lock should be held upon entering this function.
    pub fn count(&self) -> i32 {
        unsafe{ sys::libvlc_media_list_count(self.ptr) }
    }

    /// List media instance in media list at a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn item_at_index(&self, pos: i32) -> Option<Media> {
        unsafe{
            let p = sys::libvlc_media_list_item_at_index(self.ptr, pos);
            if p.is_null() { None }else{ Some(Media{ptr: p}) }
        }
    }

    /// Find index position of List media instance in media list.
    pub fn index_of_item(&self, md: &Media) -> Option<i32> {
        unsafe{
            let i = sys::libvlc_media_list_index_of_item(self.ptr, md.ptr);
            if i == -1 { None }else{ Some(i) }
        }
    }

    /// This indicates if this media list is read-only from a user point of view.
    pub fn is_readonly(&self) -> bool {
        unsafe{ if sys::libvlc_media_list_is_readonly(self.ptr) == 0 { false }else{ true } }
    }

    /// Get lock on media list items
    pub fn lock(&self) {
        unsafe{ sys::libvlc_media_list_lock(self.ptr); }
    }

    /// Release lock on media list items
    /// The libvlc_media_list_lock should be held upon entering this function.
    pub fn unlock(&self) {
        unsafe{ sys::libvlc_media_list_unlock(self.ptr); }
    }

    /// Get EventManager from this media list instance.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_list_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_list_t {
        self.ptr
    }
}

impl Drop for MediaList {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_list_release(self.ptr) };
    }
}
<commit_msg>media_list: fix crate path<commit_after>// Copyright (c) 2015 T. Okubo
// This file is part of vlc-rs.
// Licensed under the MIT license, see the LICENSE file.

use crate::sys;
use crate::{Instance, Media, EventManager};

pub struct MediaList {
    pub(crate) ptr: *mut sys::libvlc_media_list_t,
}

impl MediaList {
    /// Create an empty media list.
    pub fn new(instance: &Instance) -> Option<MediaList> {
        unsafe{
            let p = sys::libvlc_media_list_new(instance.ptr);
            if p.is_null() { None }else{ Some(MediaList{ptr: p}) }
        }
    }

    /// Associate media instance with this media list instance.
    /// If another media instance was present it will be released. The libvlc_media_list_lock should NOT be held upon entering this function.
    pub fn set_media(&self, md: &Media) {
        unsafe{ sys::libvlc_media_list_set_media(self.ptr, md.ptr); }
    }

    /// Get media instance from this media list instance.
    /// The MediaList::lock should NOT be held upon entering this function.
    pub fn media(&self) -> Option<Media> {
        unsafe{
            let p = sys::libvlc_media_list_media(self.ptr);
            if p.is_null() { None }else{ Some(Media{ptr: p}) }
        }
    }

    /// Add media instance to media list.
    /// The MediaList::lock should be held upon entering this function.
    pub fn add_media(&self, md: &Media) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_add_media(self.ptr, md.ptr) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Insert media instance in media list on a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn insert_media(&self, md: &Media, pos: i32) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_insert_media(self.ptr, md.ptr, pos) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Remove media instance from media list on a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn remove_index(&self, pos: i32) -> Result<(), ()> {
        unsafe{
            if sys::libvlc_media_list_remove_index(self.ptr, pos) == 0 { Ok(()) }else{ Err(()) }
        }
    }

    /// Get count on media list items.
    /// The MediaList::lock should be held upon entering this function.
    pub fn count(&self) -> i32 {
        unsafe{ sys::libvlc_media_list_count(self.ptr) }
    }

    /// List media instance in media list at a position.
    /// The MediaList::lock should be held upon entering this function.
    pub fn item_at_index(&self, pos: i32) -> Option<Media> {
        unsafe{
            let p = sys::libvlc_media_list_item_at_index(self.ptr, pos);
            if p.is_null() { None }else{ Some(Media{ptr: p}) }
        }
    }

    /// Find index position of List media instance in media list.
    pub fn index_of_item(&self, md: &Media) -> Option<i32> {
        unsafe{
            let i = sys::libvlc_media_list_index_of_item(self.ptr, md.ptr);
            if i == -1 { None }else{ Some(i) }
        }
    }

    /// This indicates if this media list is read-only from a user point of view.
    pub fn is_readonly(&self) -> bool {
        unsafe{ if sys::libvlc_media_list_is_readonly(self.ptr) == 0 { false }else{ true } }
    }

    /// Get lock on media list items
    pub fn lock(&self) {
        unsafe{ sys::libvlc_media_list_lock(self.ptr); }
    }

    /// Release lock on media list items
    /// The libvlc_media_list_lock should be held upon entering this function.
    pub fn unlock(&self) {
        unsafe{ sys::libvlc_media_list_unlock(self.ptr); }
    }

    /// Get EventManager from this media list instance.
    pub fn event_manager<'a>(&'a self) -> EventManager<'a> {
        unsafe{
            let p = sys::libvlc_media_list_event_manager(self.ptr);
            assert!(!p.is_null());
            EventManager{ptr: p, _phantomdata: ::std::marker::PhantomData}
        }
    }

    /// Returns raw pointer
    pub fn raw(&self) -> *mut sys::libvlc_media_list_t {
        self.ptr
    }
}

impl Drop for MediaList {
    fn drop(&mut self) {
        unsafe{ sys::libvlc_media_list_release(self.ptr) };
    }
}
<|endoftext|>