<commit_before>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! DHT node table implementation based on Kademlia.
//!
//! See [original paper](http://pdos.csail.mit.edu/%7Epetar/papers/maymounkov-kademlia-lncs.pdf)
//! for details. The most essential difference is that when k-bucket is full,
//! no RPC call is done. It is up to upper-level code to ensure proper clean up
//! using `pop_oldest` call.

use std::cmp;
use std::fmt::Debug;
use std::collections::VecDeque;

use super::GenericId;
use super::GenericNodeTable;
use super::Node;

// TODO(divius): make public?
static BUCKET_SIZE: usize = 32;
static HASH_SIZE: usize = 64;

/// Kademlia node table.
///
/// Keeps nodes in a number of k-buckets (equal to bit size of ID in a system,
/// usually 160), where N-th k-bucket contains nodes with distance
/// from 2^N to 2^(N+1) from our node.
pub struct KNodeTable<TId, TAddr> {
    this_id: TId,
    hash_size: usize,
    // TODO(divius): convert to more appropriate data structure
    buckets: Vec<KBucket<TId, TAddr>>,
}

/// K-bucket - structure for keeping last nodes in Kademlia.
struct KBucket<TId, TAddr> {
    data: VecDeque<Node<TId, TAddr>>,
    size: usize,
}

impl<TId, TAddr> KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    /// Create a new node table.
    ///
    /// `this_id` -- ID of the current node (used to calculate metrics).
    pub fn new(this_id: TId) -> KNodeTable<TId, TAddr> {
        KNodeTable::with_details(this_id, BUCKET_SIZE, HASH_SIZE)
    }

    // TODO(divius): make public?
    fn with_details(this_id: TId, bucket_size: usize,
                    hash_size: usize) -> KNodeTable<TId, TAddr> {
        KNodeTable {
            this_id: this_id,
            hash_size: hash_size,
            buckets: (0..hash_size).map(
                              |_| KBucket::new(bucket_size)).collect(),
        }
    }

    #[inline]
    fn distance(id1: &TId, id2: &TId) -> TId {
        id1.bitxor(id2)
    }

    fn bucket_number(&self, id: &TId) -> usize {
        let diff = KNodeTable::<TId, TAddr>::distance(&self.this_id, id);
        debug_assert!(!diff.is_zero());
        let res = diff.bits() - 1;
        debug!("ID {:?} relative to own ID {:?} falls into bucket {:?}",
               id, self.this_id, res);
        res
    }
}

impl<TId, TAddr> GenericNodeTable<TId, TAddr> for KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug + Sync + Send {
    fn random_id(&self) -> TId {
        TId::gen(self.hash_size)
    }

    fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        assert!(node.id != self.this_id);
        let bucket = self.bucket_number(&node.id);
        self.buckets[bucket].update(node)
    }

    fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        debug_assert!(count > 0);
        assert!(*id != self.this_id);
        let bucket = self.bucket_number(id);
        self.buckets[bucket].find(id, count)
    }

    fn pop_oldest(&mut self) -> Vec<Node<TId, TAddr>> {
        // For every full k-bucket, pop the last.
        // TODO(divius): TTL expiration?
        self.buckets.iter_mut()
            .filter(|b| { !b.data.is_empty() && b.size == b.data.len() })
            .map(|b| b.data.pop_front().unwrap())
            .collect()
    }
}

impl<TId, TAddr> KBucket<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    pub fn new(k: usize) -> KBucket<TId, TAddr> {
        assert!(k > 0);
        KBucket {
            data: VecDeque::new(),
            size: k
        }
    }

    pub fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        if self.data.iter().any(|x| x.id == node.id) {
            self.update_position(node.clone());
            debug!("Promoted node {:?} to the top of kbucket", node);
            true
        }
        else if self.data.len() == self.size {
            debug!("Not adding new node {:?} to kbucket - no space left", node);
            false
        }
        else {
            self.data.push_back(node.clone());
            debug!("Added new node {:?} to kbucket", node);
            true
        }
    }

    pub fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        let sort_fn = |a: &Node<TId, TAddr>, b: &Node<TId, TAddr>| {
            KNodeTable::<TId, TAddr>::distance(id, &a.id)
                .cmp(&KNodeTable::<TId, TAddr>::distance(id, &b.id))
        };
        let mut data_copy: Vec<_> = self.data.iter().map(|n| n.clone()).collect();
        data_copy.sort_by(sort_fn);
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    fn update_position(&mut self, node: Node<TId, TAddr>) {
        // TODO(divius): 1. optimize, 2. make it less ugly
        let mut new_data = VecDeque::with_capacity(self.data.len());
        new_data.extend(self.data.iter()
                        .filter(|x| x.id != node.id)
                        .map(|x| x.clone()));
        new_data.push_back(node.clone());
        self.data = new_data;
    }
}

#[cfg(test)]
mod test {
    use std::net;

    use super::super::GenericNodeTable;
    use super::super::Node;

    use super::HASH_SIZE;
    use super::KBucket;
    use super::KNodeTable;

    use super::super::utils::test;
    type TestsIdType = test::IdType;
    use super::super::base::GenericId;

    fn prepare(count: u8) -> KBucket<TestsIdType, net::SocketAddr> {
        KBucket {
            data: (0..count).map(|i| test::new_node(test::make_id(i))).collect(),
            size: 3,
        }
    }

    fn assert_node_list_eq(expected: &[&Node<TestsIdType, net::SocketAddr>], actual: &Vec<Node<TestsIdType, net::SocketAddr>>) {
        let act: Vec<TestsIdType> = actual.iter()
            .map(|n| n.id.clone()).collect();
        let exp: Vec<TestsIdType> = expected.iter()
            .map(|n| n.id.clone()).collect();
        assert_eq!(exp, act);
    }

    #[test]
    fn test_nodetable_new() {
        let n = KNodeTable::<u64, ()>::new(42);
        assert_eq!(HASH_SIZE, n.buckets.len());
    }

    #[test]
    fn test_nodetable_bucket_number() {
        let n = KNodeTable::<u64, ()>::new(42);
        let id = 41;
        // 42 xor 41 == 3
        assert_eq!(1, n.bucket_number(&id));
    }

    #[test]
    fn test_nodetable_pop_oldest() {
        let mut n = KNodeTable::<TestsIdType, net::SocketAddr>::with_details(
            test::make_id(42), 2, HASH_SIZE);
        n.update(&test::new_node(test::make_id(41)));
        n.update(&test::new_node(test::make_id(43)));
        n.update(&test::new_node(test::make_id(40)));
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(2, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(1, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        assert_eq!(test::make_id(40), n.buckets[1].data[0].id);
    }

    #[test]
    fn test_nodetable_find() {
        let n = KNodeTable {
            buckets: vec![prepare(1), prepare(3), prepare(1)],
            this_id: test::make_id(0),
            hash_size: HASH_SIZE,
        };
        // 0 xor 3 = 3, 1 xor 3 = 2, 2 xor 3 = 1
        let id = test::make_id(3);
        assert_node_list_eq(&[&n.buckets[1].data[2]],
                            &n.find(&id, 1));
    }

    #[test]
    fn test_nodetable_update() {
        let mut n = KNodeTable::with_details(
            test::make_id(42), 1, HASH_SIZE);
        let node = test::new_node(test::make_id(41));
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
    }

    #[test]
    fn test_nodetable_random_id() {
        let n = KNodeTable::<u64, ()>::with_details(
            42, 1, HASH_SIZE);
        for _ in 0..100 {
            assert!(n.random_id().bits() <= HASH_SIZE);
        }
        assert!(n.random_id() != n.random_id());
    }

    #[test]
    fn test_kbucket_new() {
        let b = KBucket::<TestsIdType, net::SocketAddr>::new(3);
        assert_eq!(0, b.data.len());
        assert_eq!(3, b.size);
    }

    #[test]
    fn test_kbucket_update_unknown() {
        let mut b = prepare(1);
        let node = test::new_node(test::make_id(42));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_known() {
        let mut b = prepare(2);
        let node = test::new_node(test::make_id(0));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_conflict() {
        let mut b = prepare(3);  // 3 is size
        let node = test::new_node(test::make_id(42));
        assert!(!b.update(&node))
    }

    #[test]
    fn test_kbucket_find() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2]], &b.find(&id, 1));
        assert_node_list_eq(&[&b.data[2], &b.data[0]], &b.find(&id, 2));
    }

    #[test]
    fn test_kbucket_find_too_much() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2], &b.data[0], &b.data[1]],
                            &b.find(&id, 100));
    }
}
<commit_msg>Panic with a nicer message of the distance between two IDs is greater than the number of buckets.<commit_after>// Copyright 2014 Dmitry "Divius" Tantsur <divius.inside@gmail.com>
//
// 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.
//

//! DHT node table implementation based on Kademlia.
//!
//! See [original paper](http://pdos.csail.mit.edu/%7Epetar/papers/maymounkov-kademlia-lncs.pdf)
//! for details. The most essential difference is that when k-bucket is full,
//! no RPC call is done. It is up to upper-level code to ensure proper clean up
//! using `pop_oldest` call.

use std::cmp;
use std::fmt::Debug;
use std::collections::VecDeque;

use super::GenericId;
use super::GenericNodeTable;
use super::Node;

// TODO(divius): make public?
static BUCKET_SIZE: usize = 32;
static HASH_SIZE: usize = 64;

/// Kademlia node table.
///
/// Keeps nodes in a number of k-buckets (equal to bit size of ID in a system,
/// usually 160), where N-th k-bucket contains nodes with distance
/// from 2^N to 2^(N+1) from our node.
///
/// methods may panic if distance between two ids is greater than the
/// `hash_size`.
pub struct KNodeTable<TId, TAddr> {
    this_id: TId,
    hash_size: usize,
    // TODO(divius): convert to more appropriate data structure
    buckets: Vec<KBucket<TId, TAddr>>,
}

/// K-bucket - structure for keeping last nodes in Kademlia.
struct KBucket<TId, TAddr> {
    data: VecDeque<Node<TId, TAddr>>,
    size: usize,
}

impl<TId, TAddr> KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    /// Create a new node table.
    ///
    /// `this_id` -- ID of the current node (used to calculate metrics).
    pub fn new(this_id: TId) -> KNodeTable<TId, TAddr> {
        KNodeTable::with_details(this_id, BUCKET_SIZE, HASH_SIZE)
    }

    // TODO(divius): make public?
    fn with_details(this_id: TId, bucket_size: usize,
                    hash_size: usize) -> KNodeTable<TId, TAddr> {
        KNodeTable {
            this_id: this_id,
            hash_size: hash_size,
            buckets: (0..hash_size).map(
                              |_| KBucket::new(bucket_size)).collect(),
        }
    }

    #[inline]
    fn distance(id1: &TId, id2: &TId) -> TId {
        id1.bitxor(id2)
    }

    fn bucket_number(&self, id: &TId) -> usize {
        let diff = KNodeTable::<TId, TAddr>::distance(&self.this_id, id);
        debug_assert!(!diff.is_zero());
        let res = diff.bits() - 1;
        if res >= self.hash_size {
            panic!(format!("Distance between IDs {:?} and {:?} is {:?}, which is \
                    greater than the hash size ({:?})",
                    id, self.this_id, res, self.hash_size));
        }
        debug!("ID {:?} relative to own ID {:?} falls into bucket {:?}",
               id, self.this_id, res);
        res
    }
}

impl<TId, TAddr> GenericNodeTable<TId, TAddr> for KNodeTable<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug + Sync + Send {
    fn random_id(&self) -> TId {
        TId::gen(self.hash_size)
    }

    fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        assert!(node.id != self.this_id);
        let bucket = self.bucket_number(&node.id);
        self.buckets[bucket].update(node)
    }

    fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        debug_assert!(count > 0);
        assert!(*id != self.this_id);
        let bucket = self.bucket_number(id);
        self.buckets[bucket].find(id, count)
    }

    fn pop_oldest(&mut self) -> Vec<Node<TId, TAddr>> {
        // For every full k-bucket, pop the last.
        // TODO(divius): TTL expiration?
        self.buckets.iter_mut()
            .filter(|b| { !b.data.is_empty() && b.size == b.data.len() })
            .map(|b| b.data.pop_front().unwrap())
            .collect()
    }
}

impl<TId, TAddr> KBucket<TId, TAddr>
        where TId: GenericId,
              TAddr: Clone + Debug {
    pub fn new(k: usize) -> KBucket<TId, TAddr> {
        assert!(k > 0);
        KBucket {
            data: VecDeque::new(),
            size: k
        }
    }

    pub fn update(&mut self, node: &Node<TId, TAddr>) -> bool {
        if self.data.iter().any(|x| x.id == node.id) {
            self.update_position(node.clone());
            debug!("Promoted node {:?} to the top of kbucket", node);
            true
        }
        else if self.data.len() == self.size {
            debug!("Not adding new node {:?} to kbucket - no space left", node);
            false
        }
        else {
            self.data.push_back(node.clone());
            debug!("Added new node {:?} to kbucket", node);
            true
        }
    }

    pub fn find(&self, id: &TId, count: usize) -> Vec<Node<TId, TAddr>> {
        let sort_fn = |a: &Node<TId, TAddr>, b: &Node<TId, TAddr>| {
            KNodeTable::<TId, TAddr>::distance(id, &a.id)
                .cmp(&KNodeTable::<TId, TAddr>::distance(id, &b.id))
        };
        let mut data_copy: Vec<_> = self.data.iter().map(|n| n.clone()).collect();
        data_copy.sort_by(sort_fn);
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    fn update_position(&mut self, node: Node<TId, TAddr>) {
        // TODO(divius): 1. optimize, 2. make it less ugly
        let mut new_data = VecDeque::with_capacity(self.data.len());
        new_data.extend(self.data.iter()
                        .filter(|x| x.id != node.id)
                        .map(|x| x.clone()));
        new_data.push_back(node.clone());
        self.data = new_data;
    }
}

#[cfg(test)]
mod test {
    use std::net;

    use super::super::GenericNodeTable;
    use super::super::Node;

    use super::HASH_SIZE;
    use super::KBucket;
    use super::KNodeTable;

    use super::super::utils::test;
    type TestsIdType = test::IdType;
    use super::super::base::GenericId;

    fn prepare(count: u8) -> KBucket<TestsIdType, net::SocketAddr> {
        KBucket {
            data: (0..count).map(|i| test::new_node(test::make_id(i))).collect(),
            size: 3,
        }
    }

    fn assert_node_list_eq(expected: &[&Node<TestsIdType, net::SocketAddr>], actual: &Vec<Node<TestsIdType, net::SocketAddr>>) {
        let act: Vec<TestsIdType> = actual.iter()
            .map(|n| n.id.clone()).collect();
        let exp: Vec<TestsIdType> = expected.iter()
            .map(|n| n.id.clone()).collect();
        assert_eq!(exp, act);
    }

    #[test]
    fn test_nodetable_new() {
        let n = KNodeTable::<u64, ()>::new(42);
        assert_eq!(HASH_SIZE, n.buckets.len());
    }

    #[test]
    fn test_nodetable_bucket_number() {
        let n = KNodeTable::<u64, ()>::new(42);
        let id = 41;
        // 42 xor 41 == 3
        assert_eq!(1, n.bucket_number(&id));
    }

    #[test]
    fn test_nodetable_pop_oldest() {
        let mut n = KNodeTable::<TestsIdType, net::SocketAddr>::with_details(
            test::make_id(42), 2, HASH_SIZE);
        n.update(&test::new_node(test::make_id(41)));
        n.update(&test::new_node(test::make_id(43)));
        n.update(&test::new_node(test::make_id(40)));
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(2, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        assert_eq!(0, n.buckets[2].data.len());
        assert_eq!(1, n.buckets[1].data.len());
        assert_eq!(1, n.buckets[0].data.len());
        assert_eq!(test::make_id(40), n.buckets[1].data[0].id);
    }

    #[test]
    fn test_nodetable_find() {
        let n = KNodeTable {
            buckets: vec![prepare(1), prepare(3), prepare(1)],
            this_id: test::make_id(0),
            hash_size: HASH_SIZE,
        };
        // 0 xor 3 = 3, 1 xor 3 = 2, 2 xor 3 = 1
        let id = test::make_id(3);
        assert_node_list_eq(&[&n.buckets[1].data[2]],
                            &n.find(&id, 1));
    }

    #[test]
    #[should_panic(expected = "greater than the hash size")]
    fn test_nodetable_find_overflow() {
        let mut id1 = Vec::with_capacity(HASH_SIZE/8);
        let mut id2 = Vec::with_capacity(HASH_SIZE/8);
        id1.push(0);
        id2.push(255);
        for _ in 0..(HASH_SIZE/8) {
            id1.push(0);
            id2.push(0);
        }
        let n = KNodeTable::<_, ()>::new(id1);
        n.find(&id2, 1);
    }

    #[test]
    fn test_nodetable_update() {
        let mut n = KNodeTable::with_details(
            test::make_id(42), 1, HASH_SIZE);
        let node = test::new_node(test::make_id(41));
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
        n.update(&node);
        assert_eq!(1, n.buckets[1].data.len());
    }

    #[test]
    fn test_nodetable_random_id() {
        let n = KNodeTable::<u64, ()>::with_details(
            42, 1, HASH_SIZE);
        for _ in 0..100 {
            assert!(n.random_id().bits() <= HASH_SIZE);
        }
        assert!(n.random_id() != n.random_id());
    }

    #[test]
    fn test_kbucket_new() {
        let b = KBucket::<TestsIdType, net::SocketAddr>::new(3);
        assert_eq!(0, b.data.len());
        assert_eq!(3, b.size);
    }

    #[test]
    fn test_kbucket_update_unknown() {
        let mut b = prepare(1);
        let node = test::new_node(test::make_id(42));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_known() {
        let mut b = prepare(2);
        let node = test::new_node(test::make_id(0));
        assert!(b.update(&node));
        assert_eq!(2, b.data.len());
        assert_eq!(node.id, b.data[1].id);
    }

    #[test]
    fn test_kbucket_update_conflict() {
        let mut b = prepare(3);  // 3 is size
        let node = test::new_node(test::make_id(42));
        assert!(!b.update(&node))
    }

    #[test]
    fn test_kbucket_find() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2]], &b.find(&id, 1));
        assert_node_list_eq(&[&b.data[2], &b.data[0]], &b.find(&id, 2));
    }

    #[test]
    fn test_kbucket_find_too_much() {
        let b = prepare(3);
        // Nodes with ID's 0, 1, 2; assume our ID is also 2 (impossible IRL)
        let id = test::make_id(2);
        // 0 xor 2 = 2, 1 xor 2 = 3, 2 xor 2 = 0
        assert_node_list_eq(&[&b.data[2], &b.data[0], &b.data[1]],
                            &b.find(&id, 100));
    }
}
<|endoftext|>


<commit_before>/// Lang item required to make the normal `main` work in applications
// This is how the `start` lang item works:
// When `rustc` compiles a binary crate, it creates a `main` function that looks
// like this:
//
// ```
// #[export_name = "main"]
// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//     start(main)
// }
// ```
//
// Where `start` is this function and `main` is the binary crate's `main`
// function.
//
// The final piece is that the entry point of our program, _start, has to call
// `rustc_main`. That's covered by the `_start` function in the root of this
// crate.
use led;
use timer;

#[lang = "start"]
fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize {
    main();

    0
}

#[lang = "eh_personality"]
fn eh_personality() {
    cycle_leds();
}

#[lang = "panic_fmt"]
fn panic_fmt() {
    flash_all_leds();
}

fn cycle_leds() {
    for led in led::all().cycle() {
        led.on();
        timer::delay_ms(100);
        led.off();
    }
}

fn flash_all_leds() {
    loop {
        for led in led::all() {
            led.on();
        }
        timer::delay_ms(100);
        for led in led::all() {
            led.off();
        }
        timer::delay_ms(100);
    }
}
<commit_msg>Fix comment<commit_after>/// Lang item required to make the normal `main` work in applications
// This is how the `start` lang item works:
// When `rustc` compiles a binary crate, it creates a `main` function that looks
// like this:
//
// ```
// #[export_name = "main"]
// pub extern "C" fn rustc_main(argc: isize, argv: *const *const u8) -> isize {
//     start(main, argc, argv)
// }
// ```
//
// Where `start` is this function and `main` is the binary crate's `main`
// function.
//
// The final piece is that the entry point of our program, _start, has to call
// `rustc_main`. That's covered by the `_start` function in the root of this
// crate.
use led;
use timer;

#[lang = "start"]
fn start(main: fn(), _argc: isize, _argv: *const *const u8) -> isize {
    main();

    0
}

#[lang = "eh_personality"]
fn eh_personality() {
    cycle_leds();
}

#[lang = "panic_fmt"]
fn panic_fmt() {
    flash_all_leds();
}

fn cycle_leds() {
    for led in led::all().cycle() {
        led.on();
        timer::delay_ms(100);
        led.off();
    }
}

fn flash_all_leds() {
    loop {
        for led in led::all() {
            led.on();
        }
        timer::delay_ms(100);
        for led in led::all() {
            led.off();
        }
        timer::delay_ms(100);
    }
}
<|endoftext|>


<commit_before>// Copyright (C) 2016, 2020 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use crate::error::{Error, Result};

use std::fs::{self, DirBuilder, File};
use std::io;
use std::io::Write;
use std::ops::Drop;
use std::path::{Path, PathBuf};
use std::process::Command;
use uuid;

/// Struct used to create zip (using filesystem and zip command)
pub struct Zipper {
    args: Vec<String>,
    path: PathBuf,
}

impl Zipper {
    /// Creates new zipper
    ///
    /// # Arguments
    /// * `path`: the path to a temporary directory
    /// (zipper will create a random dir in it and clean it later)
    pub fn new(path: &str) -> Result<Zipper> {
        let uuid = uuid::Uuid::new_v4();
        let zipper_path = Path::new(path).join(uuid.to_simple().to_string());

        DirBuilder::new()
            .recursive(true)
            .create(&zipper_path)
            .map_err(|_| {
                Error::zipper(lformat!(
                    "could not create temporary directory in {path}",
                    path = path
                ))
            })?;

        Ok(Zipper {
            args: vec![],
            path: zipper_path,
        })
    }

    /// writes a content to a temporary file
    pub fn write<P: AsRef<Path>>(&mut self, path: P, content: &[u8], add_args: bool) -> Result<()> {
        let path = path.as_ref();
        let file = format!("{}", path.display());
        if path.starts_with("..") || path.is_absolute() {
            return Err(Error::zipper(lformat!(
                "file {file} refers to an absolute or a parent \
                                               path.
This is forbidden because we are supposed \
                                               to create a temporary file in a temporary dir.",
                file = file
            )));
        }
        let dest_file = self.path.join(path);
        let dest_dir = dest_file.parent().unwrap();
        if !fs::metadata(dest_dir).is_ok() {
            // dir does not exist, create it
            DirBuilder::new()
                .recursive(true)
                .create(&dest_dir)
                .map_err(|_| {
                    Error::zipper(lformat!(
                        "could not create temporary directory in {path}",
                        path = dest_dir.display()
                    ))
                })?;
        }

        if let Ok(mut f) = File::create(&dest_file) {
            if f.write_all(content).is_ok() {
                if add_args {
                    self.args.push(String::from(file));
                }
                Ok(())
            } else {
                Err(Error::zipper(lformat!(
                    "could not write to temporary file {file}",
                    file = file
                )))
            }
        } else {
            Err(Error::zipper(lformat!(
                "could not create temporary file {file}",
                file = file
            )))
        }
    }

    /// Unzip a file and deletes it afterwards
    pub fn unzip(&mut self, file: &str) -> Result<()> {
        let output = Command::new("unzip")
            .current_dir(&self.path)
            .arg(file)
            .output()
            .map_err(|e| {
                Error::zipper(lformat!(
                    "failed to execute unzip on {file}: {error}",
                    file = file,
                    error = e
                ))
            });

        output?;

        fs::remove_file(self.path.join(file))
            .map_err(|_| Error::zipper(lformat!("failed to remove file {file}", file = file)))
    }

    /// run command and copy content of file output (supposed to result from the command) to current dir
    pub fn run_command(
        &mut self,
        mut command: Command,
        command_name: &str,
        in_file: &str,
        out: &mut dyn Write,
    ) -> Result<String> {
        let res_output = command
            .args(&self.args)
            .current_dir(&self.path)
            .output()
            .map_err(|e| {
                debug!(
                    "{}",
                    lformat!(
                        "output for command {name}:\n{error}",
                        name = command_name,
                        error = e
                    )
                );
                Error::zipper(lformat!(
                    "failed to run command '{name}'",
                    name = command_name
                ))
            });
        let output = res_output?;
        if output.status.success() {
            let mut file = File::open(self.path.join(in_file)).map_err(|_| {
                debug!(
                    "{}",
                    lformat!(
                        "could not open result of command '{command}'\n\
                                           Command output:\n\
                                           {output}'",
                        command = command_name,
                        output = String::from_utf8_lossy(&output.stdout)
                    )
                );
                Error::zipper(lformat!(
                    "could not open result of command '{command}'",
                    command = command_name
                ))
            })?;
            io::copy(&mut file, out).map_err(|_| {
                Error::zipper(lformat!("error copying file '{file}'", file = in_file))
            })?;

            Ok(String::from_utf8_lossy(&output.stdout).into_owned())
        } else {
            debug!(
                "{}",
                lformat!(
                    "{command} didn't return succesfully: {output}",
                    command = command_name,
                    output = String::from_utf8_lossy(&output.stdout)
                )
            );
            Err(Error::zipper(lformat!(
                "{command} didn't return succesfully",
                command = command_name
            )))
        }
    }

    /// zip all files in zipper's tmp dir to a given file name and write to odt file
    pub fn generate_odt(&mut self, command_name: &str, odt_file: &mut dyn Write) -> Result<String> {
        let mut command = Command::new(command_name);
        command.arg("-r");
        command.arg("result.odt");
        command.arg(".");
        self.run_command(command, command_name, "result.odt", odt_file)
    }

    /// generate a pdf file into given file name
    pub fn generate_pdf(
        &mut self,
        command_name: &str,
        tex_file: &str,
        pdf_file: &mut dyn Write,
    ) -> Result<String> {
        // first pass
        let mut command = Command::new(command_name);
        command.current_dir(&self.path).arg(tex_file);
        let _ = command.output();

        // second pass
        let _ = command.output();

        // third pass
        // let mut command = Command::new(command_name);
        // command.current_dir(&self.path);
        // command.arg(tex_file);
        self.run_command(command, command_name, "result.pdf", pdf_file)
    }
}

impl Drop for Zipper {
    fn drop(&mut self) {
        if let Err(err) = fs::remove_dir_all(&self.path) {
            println!(
                "Error in zipper: could not delete temporary directory {}, error: {}",
                self.path.to_string_lossy(),
                err
            );
        }
    }
}
<commit_msg>zipper:run_command should not change the arguments<commit_after>// Copyright (C) 2016, 2020 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use crate::error::{Error, Result};

use std::fs::{self, DirBuilder, File};
use std::io;
use std::io::Write;
use std::ops::Drop;
use std::path::{Path, PathBuf};
use std::process::Command;
use uuid;

/// Struct used to create zip (using filesystem and zip command)
pub struct Zipper {
    args: Vec<String>,
    path: PathBuf,
}

impl Zipper {
    /// Creates new zipper
    ///
    /// # Arguments
    /// * `path`: the path to a temporary directory
    /// (zipper will create a random dir in it and clean it later)
    pub fn new(path: &str) -> Result<Zipper> {
        let uuid = uuid::Uuid::new_v4();
        let zipper_path = Path::new(path).join(uuid.to_simple().to_string());

        DirBuilder::new()
            .recursive(true)
            .create(&zipper_path)
            .map_err(|_| {
                Error::zipper(lformat!(
                    "could not create temporary directory in {path}",
                    path = path
                ))
            })?;

        Ok(Zipper {
            args: vec![],
            path: zipper_path,
        })
    }

    /// writes a content to a temporary file
    pub fn write<P: AsRef<Path>>(&mut self, path: P, content: &[u8], add_args: bool) -> Result<()> {
        let path = path.as_ref();
        let file = format!("{}", path.display());
        if path.starts_with("..") || path.is_absolute() {
            return Err(Error::zipper(lformat!(
                "file {file} refers to an absolute or a parent \
                                               path.
This is forbidden because we are supposed \
                                               to create a temporary file in a temporary dir.",
                file = file
            )));
        }
        let dest_file = self.path.join(path);
        let dest_dir = dest_file.parent().unwrap();
        if !fs::metadata(dest_dir).is_ok() {
            // dir does not exist, create it
            DirBuilder::new()
                .recursive(true)
                .create(&dest_dir)
                .map_err(|_| {
                    Error::zipper(lformat!(
                        "could not create temporary directory in {path}",
                        path = dest_dir.display()
                    ))
                })?;
        }

        if let Ok(mut f) = File::create(&dest_file) {
            if f.write_all(content).is_ok() {
                if add_args {
                    self.args.push(String::from(file));
                }
                Ok(())
            } else {
                Err(Error::zipper(lformat!(
                    "could not write to temporary file {file}",
                    file = file
                )))
            }
        } else {
            Err(Error::zipper(lformat!(
                "could not create temporary file {file}",
                file = file
            )))
        }
    }

    /// Unzip a file and deletes it afterwards
    pub fn unzip(&mut self, file: &str) -> Result<()> {
        let output = Command::new("unzip")
            .current_dir(&self.path)
            .arg(file)
            .output()
            .map_err(|e| {
                Error::zipper(lformat!(
                    "failed to execute unzip on {file}: {error}",
                    file = file,
                    error = e
                ))
            });

        output?;

        fs::remove_file(self.path.join(file))
            .map_err(|_| Error::zipper(lformat!("failed to remove file {file}", file = file)))
    }

    /// run command and copy content of file output (supposed to result from the command) to current dir
    pub fn run_command(
        &mut self,
        mut command: Command,
        command_name: &str,
        in_file: &str,
        out: &mut dyn Write,
    ) -> Result<String> {
        let res_output = command
            .current_dir(&self.path)
            .output()
            .map_err(|e| {
                debug!(
                    "{}",
                    lformat!(
                        "output for command {name}:\n{error}",
                        name = command_name,
                        error = e
                    )
                );
                Error::zipper(lformat!(
                    "failed to run command '{name}'",
                    name = command_name
                ))
            });
        let output = res_output?;
        if output.status.success() {
            let mut file = File::open(self.path.join(in_file)).map_err(|_| {
                debug!(
                    "{}",
                    lformat!(
                        "could not open result of command '{command}'\n\
                                           Command output:\n\
                                           {output}'",
                        command = command_name,
                        output = String::from_utf8_lossy(&output.stdout)
                    )
                );
                Error::zipper(lformat!(
                    "could not open result of command '{command}'",
                    command = command_name
                ))
            })?;
            io::copy(&mut file, out).map_err(|_| {
                Error::zipper(lformat!("error copying file '{file}'", file = in_file))
            })?;

            Ok(String::from_utf8_lossy(&output.stdout).into_owned())
        } else {
            debug!(
                "{}",
                lformat!(
                    "{command} didn't return succesfully: {output}",
                    command = command_name,
                    output = String::from_utf8_lossy(&output.stdout)
                )
            );
            Err(Error::zipper(lformat!(
                "{command} didn't return succesfully",
                command = command_name
            )))
        }
    }

    /// zip all files in zipper's tmp dir to a given file name and write to odt file
    pub fn generate_odt(&mut self, command_name: &str, odt_file: &mut dyn Write) -> Result<String> {
        let mut command = Command::new(command_name);
        command.arg("-r");
        command.arg("result.odt");
        command.arg(".");
        self.run_command(command, command_name, "result.odt", odt_file)
    }

    /// generate a pdf file into given file name
    pub fn generate_pdf(
        &mut self,
        command_name: &str,
        tex_file: &str,
        pdf_file: &mut dyn Write,
    ) -> Result<String> {
        // first pass
        let mut command = Command::new(command_name);
        command.current_dir(&self.path).arg(tex_file);
        let _ = command.output();

        // second pass
        let _ = command.output();

        // third pass
        // let mut command = Command::new(command_name);
        // command.current_dir(&self.path);
        // command.arg(tex_file);
        self.run_command(command, command_name, "result.pdf", pdf_file)
    }
}

impl Drop for Zipper {
    fn drop(&mut self) {
        if let Err(err) = fs::remove_dir_all(&self.path) {
            println!(
                "Error in zipper: could not delete temporary directory {}, error: {}",
                self.path.to_string_lossy(),
                err
            );
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2012 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.

//! Traits for the built-in operators

#[allow(missing_doc)];

#[lang="drop"]
pub trait Drop {
    fn drop(&mut self);
}

#[lang="add"]
pub trait Add<RHS,Result> {
    fn add(&self, rhs: &RHS) -> Result;
}

#[lang="sub"]
pub trait Sub<RHS,Result> {
    fn sub(&self, rhs: &RHS) -> Result;
}

#[lang="mul"]
pub trait Mul<RHS,Result> {
    fn mul(&self, rhs: &RHS) -> Result;
}

#[lang="div"]
pub trait Div<RHS,Result> {
    fn div(&self, rhs: &RHS) -> Result;
}

#[lang="rem"]
pub trait Rem<RHS,Result> {
    fn rem(&self, rhs: &RHS) -> Result;
}

#[lang="neg"]
pub trait Neg<Result> {
    fn neg(&self) -> Result;
}

#[lang="not"]
pub trait Not<Result> {
    fn not(&self) -> Result;
}

#[lang="bitand"]
pub trait BitAnd<RHS,Result> {
    fn bitand(&self, rhs: &RHS) -> Result;
}

#[lang="bitor"]
pub trait BitOr<RHS,Result> {
    fn bitor(&self, rhs: &RHS) -> Result;
}

#[lang="bitxor"]
pub trait BitXor<RHS,Result> {
    fn bitxor(&self, rhs: &RHS) -> Result;
}

#[lang="shl"]
pub trait Shl<RHS,Result> {
    fn shl(&self, rhs: &RHS) -> Result;
}

#[lang="shr"]
pub trait Shr<RHS,Result> {
    fn shr(&self, rhs: &RHS) -> Result;
}

#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, index: &Index) -> Result;
}

#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use ops::Drop;

    // Overhead of dtors

    struct HasDtor {
        x: int
    }

    impl Drop for HasDtor {
        fn drop(&mut self) {
        }
    }

    #[bench]
    fn alloc_obj_with_dtor(bh: &mut BenchHarness) {
        do bh.iter {
            HasDtor { x : 10 };
        }
    }
}
<commit_msg>Document std::ops.<commit_after>// Copyright 2012 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.

// So we don't have to document the actual methods on the traits.
#[allow(missing_doc)];

/*!
 *
 * Traits for the built-in operators. Implementing these traits allows you to get
 * an effect similar to oveloading operators.
 *
 * The values for the right hand side of an operator are automatically
 * borrowed, so `a + b` is sugar for `a.add(&b)`.
 *
 * # Example
 *
 * This example creates a `Point` struct that implements `Add` and `Sub`, and then
 * demonstrates adding and subtracting two `Point`s.
 *
 * ```rust
 * use std::ops::Add;
 * use std::ops::Sub;
 *
 * struct Point {
 *     x: int,
 *     y: int
 * }
 *
 * impl Add<Point, Point> for Point {
 *     fn add(&self, other: &Point) -> Point {
 *         Point {x: self.x + other.x, y: self.y + other.y}
 *     }
 * }
 *
 * impl Sub<Point, Point> for Point {
 *     fn sub(&self, other: &Point) -> Point {
 *         Point {x: self.x - other.x, y: self.y - other.y}
 *     }
 * }
 * fn main() {
 *     println(format!("{:?}", Point {x: 1, y: 0} + Point {x: 2, y: 3}));
 *     println(format!("{:?}", Point {x: 1, y: 0} - Point {x: 2, y: 3}));
 * }
 * ```
 *
 * See the documentation for each trait for a minimum implementation that prints
 * something to the screen.
 *
 */

/**
 *
 * The `Drop` trait is used to run some code when a value goes out of scope. This
 * is sometimes called a 'destructor'.
 *
 * # Example
 *
 * A trivial implementation of `Drop`. The `drop` method is called when `_x` goes
 * out of scope, and therefore `main` prints `Dropping!`.
 *
 * ```rust
 * use std::ops::Drop;
 *
 * struct HasDrop;
 *
 * impl Drop for HasDrop {
 *   fn drop(&mut self) {
 *       println("Dropping!");
 *   }
 * }
 *
 * fn main() {
 *   let _x = HasDrop;
 * }
 * ```
 */
#[lang="drop"]
pub trait Drop {
    fn drop(&mut self);
}

/**
 *
 * The `Add` trait is used to override the functionality of `+`.
 *
 * # Example
 *
 * A trivial implementation of `Add`. When `Foo + Foo` happens, it ends up
 * calling `add`, and therefore, `main` prints `Adding!`.
 *
 * ```rust
 * use std::ops::Add;
 *
 * struct Foo;
 *
 * impl Add<Foo, Foo> for Foo {
 *     fn add(&self, _rhs: &Foo) -> Foo {
 *       println("Adding!");
 *       *self
 *   }
 * }
 *
 * fn main() {
 *   Foo + Foo;
 * }
 * ```
 */
#[lang="add"]
pub trait Add<RHS,Result> {
    fn add(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Sub` trait is used to override the functionality of `-`.
 *
 * # Example
 *
 * A trivial implementation of `Sub`. When `Foo - Foo` happens, it ends up
 * calling `sub`, and therefore, `main` prints `Subtracting!`.
 *
 * ```
 * use std::ops::Sub;
 *
 * struct Foo;
 *
 * impl Sub<Foo, Foo> for Foo {
 *     fn sub(&self, _rhs: &Foo) -> Foo {
 *         println("Subtracting!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo - Foo;
 * }
 * ```
 */
#[lang="sub"]
pub trait Sub<RHS,Result> {
    fn sub(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Mul` trait is used to override the functionality of `*`.
 *
 * # Example
 *
 * A trivial implementation of `Mul`. When `Foo * Foo` happens, it ends up
 * calling `mul`, and therefore, `main` prints `Multiplying!`.
 *
 * ```rust
 * use std::ops::Mul;
 *
 * struct Foo;
 *
 * impl Mul<Foo, Foo> for Foo {
 *     fn mul(&self, _rhs: &Foo) -> Foo {
 *         println("Multiplying!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo * Foo;
 * }
 * ```
 */
#[lang="mul"]
pub trait Mul<RHS,Result> {
    fn mul(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Div` trait is used to override the functionality of `/`.
 *
 * # Example
 *
 * A trivial implementation of `Div`. When `Foo / Foo` happens, it ends up
 * calling `div`, and therefore, `main` prints `Dividing!`.
 *
 * ```
 * use std::ops::Div;
 *
 * struct Foo;
 *
 * impl Div<Foo, Foo> for Foo {
 *     fn div(&self, _rhs: &Foo) -> Foo {
 *         println("Dividing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo / Foo;
 * }
 * ```
 */
#[lang="div"]
pub trait Div<RHS,Result> {
    fn div(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Rem` trait is used to override the functionality of `%`.
 *
 * # Example
 *
 * A trivial implemtnation of `Rem`. When `Foo % Foo` happens, it ends up
 * calling `rem`, and therefore, `main` prints `Remainder-ing!`.
 *
 * ```
 * use std::ops::Rem;
 *
 * struct Foo;
 *
 * impl Rem<Foo, Foo> for Foo {
 *     fn rem(&self, _rhs: &Foo) -> Foo {
 *         println("Remainder-ing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo % Foo;
 * }
 * ```
 */
#[lang="rem"]
pub trait Rem<RHS,Result> {
    fn rem(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Neg` trait is used to override the functionality of unary `-`.
 *
 * # Example
 *
 * A trivial implemtnation of `Neg`. When `-Foo` happens, it ends up calling
 * `neg`, and therefore, `main` prints `Negating!`.
 *
 * ```
 * use std::ops::Neg;
 *
 * struct Foo;
 *
 * impl Neg<Foo> for Foo {
 *     fn neg(&self) -> Foo {
 *         println("Negating!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     -Foo;
 * }
 * ```
 */
#[lang="neg"]
pub trait Neg<Result> {
    fn neg(&self) -> Result;
}

/**
 *
 * The `Not` trait is used to override the functionality of `!`.
 *
 * # Example
 *
 * A trivial implementation of `Not`. When `!Foo` happens, it ends up calling
 * `not`, and therefore, `main` prints `Not-ing!`.
 *
 * ```
 * use std::ops::Not;
 *
 * struct Foo;
 *
 * impl Not<Foo> for Foo {
 *     fn not(&self) -> Foo {
 *         println("Not-ing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     !Foo;
 * }
 * ```
 */
#[lang="not"]
pub trait Not<Result> {
    fn not(&self) -> Result;
}

/**
 *
 * The `BitAnd` trait is used to override the functionality of `&`.
 *
 * # Example
 *
 * A trivial implementation of `BitAnd`. When `Foo & Foo` happens, it ends up
 * calling `bitand`, and therefore, `main` prints `Bitwise And-ing!`.
 *
 * ```
 * use std::ops::BitAnd;
 *
 * struct Foo;
 *
 * impl BitAnd<Foo, Foo> for Foo {
 *     fn bitand(&self, _rhs: &Foo) -> Foo {
 *         println("Bitwise And-ing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo & Foo;
 * }
 * ```
 */
#[lang="bitand"]
pub trait BitAnd<RHS,Result> {
    fn bitand(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `BitOr` trait is used to override the functionality of `|`.
 *
 * # Example
 *
 * A trivial implementation of `BitOr`. When `Foo | Foo` happens, it ends up
 * calling `bitor`, and therefore, `main` prints `Bitwise Or-ing!`.
 *
 * ```
 * use std::ops::BitOr;
 *
 * struct Foo;
 *
 * impl BitOr<Foo, Foo> for Foo {
 *     fn bitor(&self, _rhs: &Foo) -> Foo {
 *         println("Bitwise Or-ing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo | Foo;
 * }
 * ```
 */
#[lang="bitor"]
pub trait BitOr<RHS,Result> {
    fn bitor(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `BitXor` trait is used to override the functionality of `^`.
 *
 * # Example
 *
 * A trivial implementation of `BitXor`. When `Foo ^ Foo` happens, it ends up
 * calling `bixtor`, and therefore, `main` prints `Bitwise Xor-ing!`.
 *
 * ```
 * use std::ops::BitXor;
 *
 * struct Foo;
 *
 * impl BitXor<Foo, Foo> for Foo {
 *     fn bitxor(&self, _rhs: &Foo) -> Foo {
 *         println("Bitwise Xor-ing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo ^ Foo;
 * }
 * ```
 */
#[lang="bitxor"]
pub trait BitXor<RHS,Result> {
    fn bitxor(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Shl` trait is used to override the functionality of `<<`.
 *
 * # Example
 *
 * A trivial implementation of `Shl`. When `Foo << Foo` happens, it ends up
 * calling `shl`, and therefore, `main` prints `Shifting left!`.
 *
 * ```
 * use std::ops::Shl;
 *
 * struct Foo;
 *
 * impl Shl<Foo, Foo> for Foo {
 *     fn shl(&self, _rhs: &Foo) -> Foo {
 *         println("Shifting left!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo << Foo;
 * }
 * ```
 */
#[lang="shl"]
pub trait Shl<RHS,Result> {
    fn shl(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Shr` trait is used to override the functionality of `>>`.
 *
 * # Example
 *
 * A trivial implementation of `Shr`. When `Foo >> Foo` happens, it ends up
 * calling `shr`, and therefore, `main` prints `Shifting right!`.
 *
 * ```
 * use std::ops::Shr;
 *
 * struct Foo;
 *
 * impl Shr<Foo, Foo> for Foo {
 *     fn shr(&self, _rhs: &Foo) -> Foo {
 *         println("Shifting right!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo >> Foo;
 * }
 * ```
 */
#[lang="shr"]
pub trait Shr<RHS,Result> {
    fn shr(&self, rhs: &RHS) -> Result;
}

/**
 *
 * The `Index` trait is used to override the functionality of indexing operations
 * like `arr[idx]`.
 *
 * # Example
 *
 * A trivial implementation of `Index`. When `Foo[idx]` happens, it ends up
 * calling `index`, and therefore, `main` prints `Indexing!`.
 *
 * ```
 * use std::ops::Index;
 *
 * struct Foo;
 *
 * impl Index<Foo, Foo> for Foo {
 *     fn index(&self, _rhs: &Foo) -> Foo {
 *         println("Indexing!");
 *         *self
 *     }
 * }
 *
 * fn main() {
 *     Foo[Foo];
 * }
 * ```
 */
#[lang="index"]
pub trait Index<Index,Result> {
    fn index(&self, index: &Index) -> Result;
}

#[cfg(test)]
mod bench {

    use extra::test::BenchHarness;
    use ops::Drop;

    // Overhead of dtors

    struct HasDtor {
        x: int
    }

    impl Drop for HasDtor {
        fn drop(&mut self) {
        }
    }

    #[bench]
    fn alloc_obj_with_dtor(bh: &mut BenchHarness) {
        do bh.iter {
            HasDtor { x : 10 };
        }
    }
}
<|endoftext|>


<commit_before>use std::default::Default;
use std::collections::BTreeMap;

use url::{Url, ParseError};
use sidekiq::{Job, JobOpts};
use serde_json::value::Value;
use url_serde::Serde;
use html5ever::tokenizer::{TokenSink, Token, TagToken, TokenSinkResult};

#[derive(Serialize, Debug)]
pub struct Page {
    pub url: Serde<Url>,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub urls: Vec<Serde<Url>>,
}

impl TokenSink for Page {
    type Handle = ();

    fn process_token(&mut self, token: Token) -> TokenSinkResult<()> {
        match token {
            TagToken(tag) => {
                match tag.name {
                    local_name!("a") => {
                        for attr in tag.attrs.iter() {
                            if attr.name.local.to_string() == "href" {
                                match self.can_enqueue(&attr.value) {
                                    Some(u) => {
                                        self.urls.push(Serde(u));
                                    }
                                    None => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        TokenSinkResult::Continue
    }
}

impl Page {
    pub fn new(url: Url, document: String, headers: BTreeMap<String, String>) -> Self {
        Page {
            url: Serde(url),
            document: document,
            headers: headers,
            urls: Vec::new(),
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts =
            JobOpts { queue: maman_name!().to_string().to_lowercase(), ..Default::default() };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        json!({
            "url": &self.url,
            "document": &self.document,
            "headers": &self.headers,
            "urls": &self.urls,
        })
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.url.join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.url == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.url.domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}
<commit_msg>Use sidekiq pub Value<commit_after>use std::default::Default;
use std::collections::BTreeMap;

use url::{Url, ParseError};
use sidekiq::{Job, JobOpts, Value};
use url_serde::Serde;
use html5ever::tokenizer::{TokenSink, Token, TagToken, TokenSinkResult};

#[derive(Serialize, Debug)]
pub struct Page {
    pub url: Serde<Url>,
    pub document: String,
    pub headers: BTreeMap<String, String>,
    pub urls: Vec<Serde<Url>>,
}

impl TokenSink for Page {
    type Handle = ();

    fn process_token(&mut self, token: Token) -> TokenSinkResult<()> {
        match token {
            TagToken(tag) => {
                match tag.name {
                    local_name!("a") => {
                        for attr in tag.attrs.iter() {
                            if attr.name.local.to_string() == "href" {
                                match self.can_enqueue(&attr.value) {
                                    Some(u) => {
                                        self.urls.push(Serde(u));
                                    }
                                    None => {}
                                }
                            }
                        }
                    }
                    _ => {}
                }
            }
            _ => {}
        }
        TokenSinkResult::Continue
    }
}

impl Page {
    pub fn new(url: Url, document: String, headers: BTreeMap<String, String>) -> Self {
        Page {
            url: Serde(url),
            document: document,
            headers: headers,
            urls: Vec::new(),
        }
    }

    pub fn to_job(&self) -> Job {
        let job_opts =
            JobOpts { queue: maman_name!().to_string().to_lowercase(), ..Default::default() };
        Job::new(maman_name!().to_string(), vec![self.as_object()], job_opts)
    }

    pub fn as_object(&self) -> Value {
        json!({
            "url": &self.url,
            "document": &self.document,
            "headers": &self.headers,
            "urls": &self.urls,
        })
    }

    fn normalize_url(&self, url: &str) -> Option<Url> {
        match Url::parse(url) {
            Ok(u) => Some(u),
            Err(ParseError::RelativeUrlWithoutBase) => Some(self.url.join(url).unwrap()),
            Err(_) => None,
        }
    }

    fn url_without_fragment(&self, url: &str) -> Option<Url> {
        match self.normalize_url(url) {
            Some(mut u) => {
                u.set_fragment(None);
                Some(u)
            }
            None => None,
        }
    }

    fn url_eq(&self, url: &Url) -> bool {
        self.url == *url
    }

    fn domain_eq(&self, url: &Url) -> bool {
        self.url.domain() == url.domain()
    }

    fn can_enqueue(&self, url: &str) -> Option<Url> {
        match self.url_without_fragment(url) {
            Some(u) => {
                match u.scheme() {
                    "http" | "https" => {
                        if !self.url_eq(&u) && self.domain_eq(&u) {
                            Some(u)
                        } else {
                            None
                        }
                    }
                    _ => None,
                }
            }
            None => None,
        }
    }
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by Matt Watson
// contributed by TeXitoi

use std::io::Write;
use std::thread;
const THREADS: usize = 20;
const MAX_ITER: usize = 50;
const VLEN: usize = 8;
const ZEROS: Vecf64 = [0.0; VLEN];

pub type Vecf64 = [f64; VLEN];

fn mul2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN {res[i] = x[i] * y[i];}
    res
}
fn add2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN {res[i] = x[i] + y[i];}
    res
}
fn sub2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN { res[i] = x[i] - y[i]; }
    res
}

pub fn mbrot8(cr: Vecf64, ci: Vecf64) -> u8 {
    let mut zr = cr;
    let mut zi = ci;
    let mut esc_bits = 0;
    for _ in 0..MAX_ITER {
        // Find Re(z)^2 and Im(z)^2
        let rr  = mul2(zr,zr);
        let ii  = mul2(zi,zi);
        // Check if we escape
        // May as well store this info in
        // same byte as output
        let mag = add2(rr, ii);
        for i in 0..VLEN {
            if mag[i] > 4.0 {esc_bits |= 128 >> i}
        }
        // If no more work, break early
        if esc_bits == 0xff {break}
        // Find Im(z^2)
        let ir = mul2(zr, zi);
        // Set Re(z^2)
        zr = sub2(rr, ii);
        // Set Im(z^2)
        zi = add2(ir, ir);
        // Add c
        zr = add2(zr, cr);
        zi = add2(zi, ci);
    }
    !esc_bits
}

fn main() {

    let size = std::env::args_os().nth(1)
        .and_then(|s| s.into_string().ok())
        .and_then(|n| n.parse().ok())
        .unwrap_or(200);
    let inv = 2.0 / size as f64;
    let mut xvals = vec![0.0; size];
    let mut yvals = vec![0.0; size];
    for i in 0..size {
        xvals[i] = i as f64 * inv - 1.5;
        yvals[i] = i as f64 * inv - 1.0;
    }
    let xloc = &xvals;
    let yloc = &yvals;

    let handles: Vec<_> = (0..THREADS).map(|e| {
        let xloc = xloc.to_vec();
        let yloc = yloc.to_vec();
        thread::spawn(move || {
        let mut rows = vec![vec![0 as u8; size / 8]; size / THREADS];
        for y in 0..size / THREADS {
            for x in 0..size / 8 {
                let mut cr = ZEROS;
                let ci = [yloc[y + e * size / THREADS]; VLEN];
                for i in 0..VLEN {
                    cr[i] = xloc[8 * x + i];
                }
                rows[y][x] = mbrot8(cr, ci);
            }
        }
        rows
        })
    }).collect();

    println!("P4\n{} {}", size, size);
    let stdout_unlocked = std::io::stdout();
    let mut stdout = stdout_unlocked.lock();
    for row in handles.into_iter().flat_map(|h| h.join().unwrap().into_iter()) {
        stdout.write_all(&row).unwrap();
    }
    stdout.flush().unwrap();
}
<commit_msg>small style cleanups<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by Matt Watson
// contributed by TeXitoi

use std::io::Write;
use std::thread;
const THREADS: usize = 20;
const MAX_ITER: usize = 50;
const VLEN: usize = 8;
const ZEROS: Vecf64 = [0.0; VLEN];

pub type Vecf64 = [f64; VLEN];

fn mul2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN { res[i] = x[i] * y[i]; }
    res
}
fn add2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN { res[i] = x[i] + y[i]; }
    res
}
fn sub2 (x: Vecf64, y: Vecf64) -> Vecf64 {
    let mut res = ZEROS;
    for i in 0..VLEN { res[i] = x[i] - y[i]; }
    res
}

pub fn mbrot8(cr: Vecf64, ci: Vecf64) -> u8 {
    let mut zr = cr;
    let mut zi = ci;
    let mut esc_bits = 0;
    for _ in 0..MAX_ITER {
        // Find Re(z)^2 and Im(z)^2
        let rr  = mul2(zr,zr);
        let ii  = mul2(zi,zi);
        // Check if we escape
        // May as well store this info in
        // same byte as output
        let mag = add2(rr, ii);
        for i in 0..VLEN {
            if mag[i] > 4.0 { esc_bits |= 128 >> i; }
        }
        // If no more work, break early
        if esc_bits == 0xff { break; }
        // Find Im(z^2)
        let ir = mul2(zr, zi);
        // Set Re(z^2)
        zr = sub2(rr, ii);
        // Set Im(z^2)
        zi = add2(ir, ir);
        // Add c
        zr = add2(zr, cr);
        zi = add2(zi, ci);
    }
    !esc_bits
}

fn main() {
    let size = std::env::args_os().nth(1)
        .and_then(|s| s.into_string().ok())
        .and_then(|n| n.parse().ok())
        .unwrap_or(200);
    let inv = 2.0 / size as f64;
    let mut xvals = vec![0.0; size];
    let mut yvals = vec![0.0; size];
    for i in 0..size {
        xvals[i] = i as f64 * inv - 1.5;
        yvals[i] = i as f64 * inv - 1.0;
    }
    let xloc = &xvals;
    let yloc = &yvals;

    assert!(size % THREADS == 0);// FIXME
    let handles: Vec<_> = (0..THREADS).map(|e| {
        let xloc = xloc.to_vec();
        let yloc = yloc.to_vec();
        thread::spawn(move || {
            let mut rows = vec![vec![0 as u8; size / 8]; size / THREADS];
            for y in 0..size / THREADS {
                for x in 0..size / 8 {
                    let mut cr = ZEROS;
                    let ci = [yloc[y + e * size / THREADS]; VLEN];
                    for i in 0..VLEN {
                        cr[i] = xloc[8 * x + i];
                    }
                    rows[y][x] = mbrot8(cr, ci);
                }
            }
            rows
        })
    }).collect();

    println!("P4\n{} {}", size, size);
    let stdout_unlocked = std::io::stdout();
    let mut stdout = stdout_unlocked.lock();
    for row in handles.into_iter().flat_map(|h| h.join().unwrap().into_iter()) {
        stdout.write_all(&row).unwrap();
    }
    stdout.flush().unwrap();
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(Term::StartDefinition),
            ";" => Ok(Term::EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Term::Number))
            .or_else(|_| Ok(Term::Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            try!(self.step_term(term))
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Term::Number(value) => self.push(value),
            Term::Word(word) => self.step_word(&word),
            Term::StartDefinition => self.store_definition(),
            Term::EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: &str) -> ForthResult {
        self.defs
            .get(word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(Term::EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Term::Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        let mut resolved_def = Code::new();
        for t in code.iter() {
            match t {
                Term::Number(_) => resolved_def.push_back(t.clone()),
                Term::Word(s) => if let Some(cs) = self.defs.get(s) {
                    resolved_def.append(&mut cs.clone());
                } else {
                    resolved_def.push_back(t.clone());
                },
                _ => unimplemented!("not even sure a definition in a definition is valid Forth"),
            }
        }
        self.defs.insert(name, resolved_def);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<commit_msg>forth: Use `?` not `try!`<commit_after>use std::collections::HashMap;
use std::collections::LinkedList;
use std::str::FromStr;

pub type Value = i32;
pub type ForthResult = Result<(), Error>;
type StackResult<T> = Result<T, Error>;

type Stack = LinkedList<Value>;
type Code = LinkedList<Term>;
type Definitions = HashMap<String, Code>;

pub struct Forth {
    code: Code,
    defs: Definitions,
    stack: Stack,
}

#[derive(Debug, PartialEq)]
pub enum Error {
    DivisionByZero,
    StackUnderflow,
    UnknownWord,
    InvalidWord,
}

#[derive(Debug, Clone)]
enum Term {
    Number(Value),
    Word(String),
    StartDefinition,
    EndDefinition,
}

impl FromStr for Term {
    type Err = ();

    fn from_str(s: &str) -> Result<Term, ()> {
        match s {
            ":" => Ok(Term::StartDefinition),
            ";" => Ok(Term::EndDefinition),
            _ => Err(()),
        }.or_else(|_| Value::from_str(s).map(Term::Number))
            .or_else(|_| Ok(Term::Word(s.to_ascii_lowercase())))
    }
}

impl Forth {
    pub fn new() -> Forth {
        Forth {
            code: LinkedList::new(),
            defs: HashMap::new(),
            stack: LinkedList::new(),
        }
    }

    pub fn stack(&self) -> Vec<Value> {
        self.stack.iter().cloned().collect()
    }

    pub fn eval(&mut self, input: &str) -> ForthResult {
        let mut new_code = Forth::into_code(input);
        self.code.append(&mut new_code);
        self.run()
    }

    fn run(&mut self) -> ForthResult {
        while let Some(term) = self.code.pop_front() {
            self.step_term(term)?
        }

        Forth::ok()
    }

    fn step_term(&mut self, term: Term) -> ForthResult {
        match term {
            Term::Number(value) => self.push(value),
            Term::Word(word) => self.step_word(&word),
            Term::StartDefinition => self.store_definition(),
            Term::EndDefinition => Err(Error::InvalidWord),
        }
    }

    fn step_word(&mut self, word: &str) -> ForthResult {
        self.defs
            .get(word)
            .ok_or(Error::UnknownWord)
            .map(Clone::clone)
            .map(|mut code| self.code.append(&mut code))
            .or_else(|_| self.step_built_in(word))
    }

    fn step_built_in(&mut self, word: &str) -> ForthResult {
        match word {
            "+" => self.bin_op(|(a, b)| Ok(a + b)),
            "-" => self.bin_op(|(a, b)| Ok(a - b)),
            "*" => self.bin_op(|(a, b)| Ok(a * b)),
            "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)),
            "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))),
            "drop" => self.pop().and(Forth::ok()),
            "swap" => self.pop_two()
                .and_then(|(a, b)| self.push(b).and(self.push(a))),
            "over" => self.pop_two()
                .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))),
            _ => Err(Error::UnknownWord),
        }
    }

    fn store_definition(&mut self) -> ForthResult {
        let mut def = LinkedList::new();

        loop {
            match self.code.pop_front() {
                Some(Term::EndDefinition) => break,
                Some(term) => def.push_back(term),
                None => return Err(Error::InvalidWord),
            }
        }

        if let Some(Term::Word(name)) = def.pop_front() {
            self.store_word(name, def)
        } else {
            Err(Error::InvalidWord)
        }
    }

    fn push(&mut self, value: Value) -> ForthResult {
        self.stack.push_back(value);
        Forth::ok()
    }

    fn pop(&mut self) -> StackResult<Value> {
        self.stack.pop_back().ok_or(Error::StackUnderflow)
    }

    fn pop_two(&mut self) -> StackResult<(Value, Value)> {
        self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b))))
    }

    fn bin_op<F>(&mut self, op: F) -> ForthResult
    where
        F: FnOnce((Value, Value)) -> StackResult<Value>,
    {
        self.pop_two()
            .and_then(op)
            .and_then(|value| self.push(value))
    }

    fn store_word(&mut self, name: String, code: Code) -> ForthResult {
        let mut resolved_def = Code::new();
        for t in code.iter() {
            match t {
                Term::Number(_) => resolved_def.push_back(t.clone()),
                Term::Word(s) => if let Some(cs) = self.defs.get(s) {
                    resolved_def.append(&mut cs.clone());
                } else {
                    resolved_def.push_back(t.clone());
                },
                _ => unimplemented!("not even sure a definition in a definition is valid Forth"),
            }
        }
        self.defs.insert(name, resolved_def);
        Forth::ok()
    }

    fn into_code(input: &str) -> LinkedList<Term> {
        input
            .split(|c: char| c.is_whitespace() || c.is_control())
            .map(Term::from_str)
            .filter(Result::is_ok)
            .map(Result::unwrap)
            .collect()
    }

    fn ok() -> ForthResult {
        Ok(())
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use schemes::{Result, KScheme, Resource, Url, VecResource};

pub struct InterruptScheme;

static IRQ_NAME: [&'static str; 15] = [
    "Programmable Interval Timer",
    "Keyboard",
    "Cascade",
    "Serial 2 and 4",
    "Serial 1 and 3",
    "Parallel 2",
    "Floppy",
    "Parallel 1",
    "Realtime Clock",
    "PCI 1",
    "PCI 2",
    "PCI 3",
    "Mouse",
    "Coprocessor",
    "IDE Primary",
    "IDE Secondary",
];

impl KScheme for InterruptScheme {
    fn scheme(&self) -> &str {
        "interrupt"
    }

    fn open(&mut self, _: &Url, _: usize) -> Result<Box<Resource>> {
        let mut string = format!("{:<6}{:<16}{}", "INT", "COUNT", "DESCRIPTION");

        {
            let interrupts = ::env().interrupts.lock();
            for interrupt in 0..interrupts.len() {
                let count = interrupts[interrupt];

                if count > 0 {
                    let description = match interrupt {
                        i @ 0x20 ... 0x30 => IRQ_NAME[i - 0x20],
                        0x80 => "System Call",
                        0x0 => "Divide by zero exception",
                        0x1 => "Debug exception",
                        0x2 => "Non-maskable interrupt",
                        0x3 => "Breakpoint exception",
                        0x4 => "Overflow exception",
                        0x5 => "Bound range exceeded exception",
                        0x6 => "Invalid opcode exception",
                        0x7 => "Device not available exception",
                        0x8 => "Double fault",
                        0xA => "Invalid TSS exception",
                        0xB => "Segment not present exception",
                        0xC => "Stack-segment fault",
                        0xD => "General protection fault",
                        0xE => "Page fault",
                        0x10 => "x87 floating-point exception",
                        0x11 => "Alignment check exception",
                        0x12 => "Machine check exception",
                        0x13 => "SIMD floating-point exception",
                        0x14 => "Virtualization exception",
                        0x1E => "Security exception",
                        _ => "Unknown Interrupt",
                    };

                    string = string + "\n" + &format!("{:<6X}{:<16}{}", interrupt, count, description);
                }
            }
        }

        Ok(box VecResource::new(Url::from_str("interrupt:"), string.into_bytes()))
    }
}
<commit_msg>Fix type mismatch<commit_after>use alloc::boxed::Box;

use schemes::{Result, KScheme, Resource, Url, VecResource};

pub struct InterruptScheme;

static IRQ_NAME: [&'static str; 16] = [
    "Programmable Interval Timer",
    "Keyboard",
    "Cascade",
    "Serial 2 and 4",
    "Serial 1 and 3",
    "Parallel 2",
    "Floppy",
    "Parallel 1",
    "Realtime Clock",
    "PCI 1",
    "PCI 2",
    "PCI 3",
    "Mouse",
    "Coprocessor",
    "IDE Primary",
    "IDE Secondary",
];

impl KScheme for InterruptScheme {
    fn scheme(&self) -> &str {
        "interrupt"
    }

    fn open(&mut self, _: &Url, _: usize) -> Result<Box<Resource>> {
        let mut string = format!("{:<6}{:<16}{}", "INT", "COUNT", "DESCRIPTION");

        {
            let interrupts = ::env().interrupts.lock();
            for interrupt in 0..interrupts.len() {
                let count = interrupts[interrupt];

                if count > 0 {
                    let description = match interrupt {
                        i @ 0x20 ... 0x30 => IRQ_NAME[i - 0x20],
                        0x80 => "System Call",
                        0x0 => "Divide by zero exception",
                        0x1 => "Debug exception",
                        0x2 => "Non-maskable interrupt",
                        0x3 => "Breakpoint exception",
                        0x4 => "Overflow exception",
                        0x5 => "Bound range exceeded exception",
                        0x6 => "Invalid opcode exception",
                        0x7 => "Device not available exception",
                        0x8 => "Double fault",
                        0xA => "Invalid TSS exception",
                        0xB => "Segment not present exception",
                        0xC => "Stack-segment fault",
                        0xD => "General protection fault",
                        0xE => "Page fault",
                        0x10 => "x87 floating-point exception",
                        0x11 => "Alignment check exception",
                        0x12 => "Machine check exception",
                        0x13 => "SIMD floating-point exception",
                        0x14 => "Virtualization exception",
                        0x1E => "Security exception",
                        _ => "Unknown Interrupt",
                    };

                    string = string + "\n" + &format!("{:<6X}{:<16}{}", interrupt, count, description);
                }
            }
        }

        Ok(box VecResource::new(Url::from_str("interrupt:"), string.into_bytes()))
    }
}
<|endoftext|>