<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.
///
/// 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));
    }
}
<commit_msg>Make new_with_details public.<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 DEFAULT_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::new_with_details(this_id, BUCKET_SIZE, DEFAULT_HASH_SIZE)
    }

    pub fn new_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::DEFAULT_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!(DEFAULT_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>::new_with_details(
            test::make_id(42), 2, DEFAULT_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: DEFAULT_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(DEFAULT_HASH_SIZE/8);
        let mut id2 = Vec::with_capacity(DEFAULT_HASH_SIZE/8);
        id1.push(0);
        id2.push(255);
        for _ in 0..(DEFAULT_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::new_with_details(
            test::make_id(42), 1, DEFAULT_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, ()>::new_with_details(
            42, 1, DEFAULT_HASH_SIZE);
        for _ in 0..100 {
            assert!(n.random_id().bits() <= DEFAULT_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, 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 crate::led;
use crate::timer;
use crate::timer::Duration;
use core::alloc::Layout;
use core::executor;
use core::panic::PanicInfo;

#[lang = "start"]
extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8)
where
    T: Termination,
{
    main();
}

#[lang = "termination"]
pub trait Termination {}

impl Termination for () {}

impl Termination for crate::result::TockResult<()> {}

#[panic_handler]
unsafe fn panic_handler(_info: &PanicInfo) -> ! {
    // Signal a panic using the LowLevelDebug capsule (if available).
    super::debug::low_level_status_code(1);

    // Flash all LEDs (if available).
    executor::block_on(async {
        let context = timer::DriverContext::create().ok().unwrap();
        let mut driver = context.create_timer_driver_unsafe();
        let timer_driver = driver.activate().ok().unwrap();
        loop {
            for led in led::all() {
                let _ = led.on();
            }
            let _ = timer_driver.sleep(Duration::from_ms(100)).await;
            for led in led::all() {
                let _ = led.off();
            }
            let _ = timer_driver.sleep(Duration::from_ms(100)).await;
        }
    });
    // Never type is not supported for T in Future
    unreachable!()
}

#[alloc_error_handler]
unsafe fn cycle_leds(_: Layout) -> ! {
    executor::block_on(async {
        let context = timer::DriverContext::create().ok().unwrap();
        let mut driver = context.create_timer_driver_unsafe();
        let timer_driver = driver.activate().ok().unwrap();
        loop {
            for led in led::all() {
                let _ = led.on();
                let _ = timer_driver.sleep(Duration::from_ms(100)).await;
                let _ = led.off();
            }
        }
    });
    // Never type is not supported for T in Future
    unreachable!()
}
<commit_msg>Remove unwraps in panic handler.<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 crate::led;
use crate::timer;
use crate::timer::Duration;
use core::alloc::Layout;
use core::executor;
use core::panic::PanicInfo;

#[lang = "start"]
extern "C" fn start<T>(main: fn() -> T, _argc: isize, _argv: *const *const u8)
where
    T: Termination,
{
    main();
}

#[lang = "termination"]
pub trait Termination {}

impl Termination for () {}

impl Termination for crate::result::TockResult<()> {}

#[panic_handler]
unsafe fn panic_handler(_info: &PanicInfo) -> ! {
    // Signal a panic using the LowLevelDebug capsule (if available).
    super::debug::low_level_status_code(1);

    // Flash all LEDs (if available).
    executor::block_on(async {
        let context = timer::DriverContext::create().ok().unwrap();
        let mut driver = context.create_timer_driver_unsafe();
        let timer_driver = driver.activate().ok().unwrap();
        loop {
            for led in led::all() {
                let _ = led.on();
            }
            let _ = timer_driver.sleep(Duration::from_ms(100)).await;
            for led in led::all() {
                let _ = led.off();
            }
            let _ = timer_driver.sleep(Duration::from_ms(100)).await;
        }
    });
    // Never type is not supported for T in Future
    unreachable!()
}

#[alloc_error_handler]
unsafe fn cycle_leds(_: Layout) -> ! {
    executor::block_on(async {
        let context = timer::DriverContext::create().ok();
        let mut driver = context.as_ref().map(|c| c.create_timer_driver_unsafe());
        let timer_driver = driver.as_mut().and_then(|d| d.activate().ok());
        loop {
            for led in led::all() {
                let _ = led.on();
            }
            if let Some(ref timer_driver) = timer_driver {
                let _ = timer_driver.sleep(Duration::from_ms(100)).await;
            }
            for led in led::all() {
                let _ = led.off();
            }
            if let Some(ref timer_driver) = timer_driver {
                let _ = timer_driver.sleep(Duration::from_ms(100)).await;
            }
        }
    });
    // Never type is not supported for T in Future
    unreachable!()
}
<|endoftext|>


<commit_before>// Copyright (C) 2016-2019 É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::book::Book;
use crate::error::{Error, Result, Source};
use crate::token::Token;

use std::convert::AsRef;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::ops::BitOr;
use std::path::Path;

use comrak::nodes::{AstNode, ListType, NodeValue};
use comrak::{parse_document, Arena, ComrakOptions};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
///
/// This is used by the renderers to only require some packages if they
/// are needed.
pub struct Features {
    pub image: bool,
    pub footnote: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub table: bool,
    pub url: bool,
    pub subscript: bool,
    pub superscript: bool,
    pub strikethrough: bool,
    pub taskitem: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
            url: false,
            subscript: false,
            superscript: false,
            strikethrough: false,
            taskitem: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
            url: self.url | rhs.url,
            subscript: self.subscript | rhs.subscript,
            superscript: self.superscript | rhs.superscript,
            strikethrough: self.strikethrough | rhs.strikethrough,
            taskitem: self.taskitem | rhs.taskitem,
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    source: Source,
    features: Features,

    html_as_text: bool,
    superscript: bool,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            source: Source::empty(),
            features: Features::new(),
            html_as_text: true,
            superscript: false,
        }
    }

    /// Creates a parser with options from a book configuration file
    pub fn from(book: &Book) -> Parser {
        let mut parser = Parser::new();
        parser.html_as_text = book.options.get_bool("crowbook.html_as_text").unwrap();
        parser.superscript = book
            .options
            .get_bool("crowbook.markdown.superscript")
            .unwrap();
        parser
    }

    /// Enable/disable HTML as text
    pub fn html_as_text(&mut self, b: bool) {
        self.html_as_text = b;
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path).map_err(|_| {
            Error::file_not_found(
                &self.source,
                lformat!("markdown file"),
                format!("{}", path.display()),
            )
        })?;
        let mut s = String::new();

        f.read_to_string(&mut s).map_err(|_| {
            Error::parser(
                &self.source,
                lformat!(
                    "file {file} contains invalid UTF-8, could not parse it",
                    file = path.display()
                ),
            )
        })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let arena = Arena::new();

        // Set options for comrak
        let mut options = ComrakOptions::default();
        options.hardbreaks = false;
        options.smart = false;
        options.ext_strikethrough = true;
        options.ext_table = true;
        options.ext_autolink = true;
        options.ext_tasklist = true;
        options.ext_superscript = self.superscript;
        options.ext_footnotes = true;
        options.ext_description_lists = true;

        let root = parse_document(&arena, s, &options);

        let mut res = self.parse_node(root)?;

        collapse(&mut res);

        find_standalone(&mut res);

        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    fn parse_node<'a>(&mut self, node: &'a AstNode<'a>) -> Result<Vec<Token>> {
        let mut inner = vec![];
        for c in node.children() {
            let mut v = self.parse_node(c)?;
            inner.append(&mut v);
        }

        inner = match node.data.borrow().value {
            NodeValue::Document => inner,
            NodeValue::BlockQuote => {
                self.features.blockquote = true;
                vec![Token::BlockQuote(inner)]
            }
            NodeValue::List(ref list) => {
                // Todo: use "tight" feature?
                match list.list_type {
                    ListType::Bullet => vec![Token::List(inner)],
                    ListType::Ordered => vec![Token::OrderedList(list.start, inner)],
                }
            }
            NodeValue::Item(_) => vec![Token::Item(inner)],
            NodeValue::DescriptionList => vec![Token::DescriptionList(inner)],
            NodeValue::DescriptionItem(_) => vec![Token::DescriptionItem(inner)],
            NodeValue::DescriptionTerm => vec![Token::DescriptionTerm(inner)],
            NodeValue::DescriptionDetails => vec![Token::DescriptionDetails(inner)],
            NodeValue::CodeBlock(ref block) => {
                let info = String::from_utf8(block.info.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8"))
                })?;
                let code = String::from_utf8(block.literal.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8"))
                })?;
                self.features.codeblock = true;
                vec![Token::CodeBlock(info, code)]
            }
            NodeValue::HtmlBlock(ref block) => {
                let text = String::from_utf8(block.literal.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8"))
                })?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            }
            NodeValue::HtmlInline(ref html) => {
                let text = String::from_utf8(html.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8"))
                })?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            }
            NodeValue::Paragraph => vec![Token::Paragraph(inner)],
            NodeValue::Heading(ref heading) => vec![Token::Header(heading.level as i32, inner)],
            NodeValue::ThematicBreak => vec![Token::Rule],
            NodeValue::FootnoteDefinition(ref def) => {
                let reference = String::from_utf8(def.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Footnote definition contains invalid UTF-8"),
                    )
                })?;
                vec![Token::FootnoteDefinition(reference, inner)]
            }
            NodeValue::Text(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Markdown file contains invalid UTF-8"),
                    )
                })?;
                vec![Token::Str(text)]
            }
            NodeValue::Code(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Markdown file contains invalid UTF-8"),
                    )
                })?;
                vec![Token::Code(text)]
            }
            NodeValue::SoftBreak => vec![Token::SoftBreak],
            NodeValue::LineBreak => vec![Token::HardBreak],
            NodeValue::Emph => vec![Token::Emphasis(inner)],
            NodeValue::TaskItem(checked) => {
                self.features.taskitem = true;
                vec![Token::TaskItem(checked, inner)]
            },
            NodeValue::Strong => vec![Token::Strong(inner)],
            NodeValue::Strikethrough => {
                self.features.strikethrough = true;
                vec![Token::Strikethrough(inner)]
            }
            NodeValue::Superscript => vec![Token::Superscript(inner)],
            NodeValue::Link(ref link) => {
                self.features.url = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Link URL contains invalid UTF-8"))
                })?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Link title contains invalid UTF-8"))
                })?;
                vec![Token::Link(url, title, inner)]
            }
            NodeValue::Image(ref link) => {
                self.features.image = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Image URL contains invalid UTF-8"))
                })?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Image title contains invalid UTF-8"))
                })?;
                vec![Token::Image(url, title, inner)]
            }
            NodeValue::FootnoteReference(ref name) => {
                let name = String::from_utf8(name.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Footnote reference contains invalid UTF-8"),
                    )
                })?;

                vec![Token::FootnoteReference(name)]
            }
            NodeValue::TableCell => vec![Token::TableCell(inner)],
            NodeValue::TableRow(header) => {
                if header {
                    vec![Token::TableHead(inner)]
                } else {
                    vec![Token::TableRow(inner)]
                }
            }
            NodeValue::Table(ref aligns) => {
                self.features.table = true;
                // TODO: actually use alignements)
                vec![Token::Table(aligns.len() as i32, inner)]
            }
        };
        Ok(inner)
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i + 1 < ast.len() {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) =
                    (&mut ast[i], token)
                {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) =
                        mem::replace(&mut inner[0], Token::Rule)
                    {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    // If paragraph only contains a link only containing an image, ok too
                    // Fixme: messy code and unnecessary clone
                    if let Token::Link(ref url, ref alt, ref mut inner) = inner[0] {
                        if inner[0].is_image() {
                            if let Token::Image(source, title, inner) =
                                mem::replace(&mut inner[0], Token::Rule)
                            {
                                Token::Link(
                                    url.clone(),
                                    alt.clone(),
                                    vec![Token::StandaloneImage(source, title, inner)],
                                )
                            } else {
                                unreachable!();
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}
<commit_msg>Fix paragraph issue in descriptionterms<commit_after>// Copyright (C) 2016-2019 É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::book::Book;
use crate::error::{Error, Result, Source};
use crate::token::Token;

use std::convert::AsRef;
use std::fs::File;
use std::io::Read;
use std::mem;
use std::ops::BitOr;
use std::path::Path;

use comrak::nodes::{AstNode, ListType, NodeValue};
use comrak::{parse_document, Arena, ComrakOptions};

#[derive(Debug, Copy, Clone, PartialEq)]
/// The list of features used in a document.
///
/// This is used by the renderers to only require some packages if they
/// are needed.
pub struct Features {
    pub image: bool,
    pub footnote: bool,
    pub blockquote: bool,
    pub codeblock: bool,
    pub ordered_list: bool,
    pub table: bool,
    pub url: bool,
    pub subscript: bool,
    pub superscript: bool,
    pub strikethrough: bool,
    pub taskitem: bool,
}

impl Features {
    /// Creates a new set of features where all are set to false
    pub fn new() -> Features {
        Features {
            image: false,
            blockquote: false,
            codeblock: false,
            ordered_list: false,
            footnote: false,
            table: false,
            url: false,
            subscript: false,
            superscript: false,
            strikethrough: false,
            taskitem: false,
        }
    }
}

impl BitOr for Features {
    type Output = Self;

    fn bitor(self, rhs: Self) -> Self {
        Features {
            image: self.image | rhs.image,
            blockquote: self.blockquote | rhs.blockquote,
            codeblock: self.codeblock | rhs.codeblock,
            ordered_list: self.ordered_list | rhs.ordered_list,
            footnote: self.footnote | rhs.footnote,
            table: self.table | rhs.table,
            url: self.url | rhs.url,
            subscript: self.subscript | rhs.subscript,
            superscript: self.superscript | rhs.superscript,
            strikethrough: self.strikethrough | rhs.strikethrough,
            taskitem: self.taskitem | rhs.taskitem,
        }
    }
}

/// A parser that reads markdown and convert it to AST (a vector of `Token`s)
///
/// This AST can then be used by various renderes.
///
/// As this Parser uses Pulldown-cmark's one, it should be able to parse most
/// *valid* CommonMark variant of Markdown.
///
/// Compared to other Markdown parser, it might fail more often on invalid code, e.g.
/// footnotes references that are not defined anywhere.
///
/// # Examples
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some *valid* Markdown[^1]\n\n[^1]: with a valid footnote");
/// assert!(result.is_ok());
/// ```
///
/// ```
/// use crowbook::Parser;
/// let mut parser = Parser::new();
/// let result = parser.parse("Some footnote pointing to nothing[^1] ");
/// assert!(result.is_err());
/// ```
pub struct Parser {
    source: Source,
    features: Features,
    ignore_paragraphs: bool,

    html_as_text: bool,
    superscript: bool,
}

impl Parser {
    /// Creates a parser
    pub fn new() -> Parser {
        Parser {
            source: Source::empty(),
            features: Features::new(),
            ignore_paragraphs: false,
            html_as_text: true,
            superscript: false,
        }
    }

    /// Creates a parser with options from a book configuration file
    pub fn from(book: &Book) -> Parser {
        let mut parser = Parser::new();
        parser.html_as_text = book.options.get_bool("crowbook.html_as_text").unwrap();
        parser.superscript = book
            .options
            .get_bool("crowbook.markdown.superscript")
            .unwrap();
        parser
    }

    /// Enable/disable HTML as text
    pub fn html_as_text(&mut self, b: bool) {
        self.html_as_text = b;
    }

    /// Sets a parser's source file
    pub fn set_source_file(&mut self, s: &str) {
        self.source = Source::new(s);
    }

    /// Parse a file and returns an AST or  an error
    pub fn parse_file<P: AsRef<Path>>(&mut self, filename: P) -> Result<Vec<Token>> {
        let path: &Path = filename.as_ref();
        let mut f = File::open(path).map_err(|_| {
            Error::file_not_found(
                &self.source,
                lformat!("markdown file"),
                format!("{}", path.display()),
            )
        })?;
        let mut s = String::new();

        f.read_to_string(&mut s).map_err(|_| {
            Error::parser(
                &self.source,
                lformat!(
                    "file {file} contains invalid UTF-8, could not parse it",
                    file = path.display()
                ),
            )
        })?;
        self.parse(&s)
    }

    /// Parse a string and returns an AST  an Error.
    pub fn parse(&mut self, s: &str) -> Result<Vec<Token>> {
        let arena = Arena::new();

        // Set options for comrak
        let mut options = ComrakOptions::default();
        options.hardbreaks = false;
        options.smart = false;
        options.ext_strikethrough = true;
        options.ext_table = true;
        options.ext_autolink = true;
        options.ext_tasklist = true;
        options.ext_superscript = self.superscript;
        options.ext_footnotes = true;
        options.ext_description_lists = true;

        let root = parse_document(&arena, s, &options);

        let mut res = self.parse_node(root)?;

        collapse(&mut res);

        find_standalone(&mut res);

        Ok(res)
    }

    /// Parse an inline string and returns a list of `Token`.
    ///
    /// This function removes the outermost `Paragraph` in most of the
    /// cases, as it is meant to be used for an inline string (e.g. metadata)
    pub fn parse_inline(&mut self, s: &str) -> Result<Vec<Token>> {
        let mut tokens = self.parse(s)?;
        // Unfortunately, parser will put all this in a paragraph, so we might need to remove it.
        if tokens.len() == 1 {
            let res = match tokens[0] {
                Token::Paragraph(ref mut v) => Some(mem::replace(v, vec![])),
                _ => None,
            };
            match res {
                Some(tokens) => Ok(tokens),
                _ => Ok(tokens),
            }
        } else {
            Ok(tokens)
        }
    }

    /// Returns the list of features used by this parser
    pub fn features(&self) -> Features {
        self.features
    }

    fn parse_node<'a>(&mut self, node: &'a AstNode<'a>) -> Result<Vec<Token>> {
        let mut inner = vec![];

        // Some special cases where we need to modifiy a bit the state of the parser between parsing inner content
        if let NodeValue::DescriptionTerm = node.data.borrow().value {
            self.ignore_paragraphs = true;
        }
        for c in node.children() {
            let mut v = self.parse_node(c)?;
            inner.append(&mut v);
        }
        // Reset state after special cases shenanigans
        if let NodeValue::DescriptionTerm = node.data.borrow().value {
            // There should be no paragraphs inside description terms
            self.ignore_paragraphs = false;
        }

        inner = match node.data.borrow().value {
            NodeValue::Document => inner,
            NodeValue::BlockQuote => {
                self.features.blockquote = true;
                vec![Token::BlockQuote(inner)]
            }
            NodeValue::List(ref list) => {
                // Todo: use "tight" feature?
                match list.list_type {
                    ListType::Bullet => vec![Token::List(inner)],
                    ListType::Ordered => vec![Token::OrderedList(list.start, inner)],
                }
            }
            NodeValue::Item(_) => vec![Token::Item(inner)],
            NodeValue::DescriptionList => vec![Token::DescriptionList(inner)],
            NodeValue::DescriptionItem(_) => vec![Token::DescriptionItem(inner)],
            NodeValue::DescriptionTerm => vec![Token::DescriptionTerm(inner)],
            NodeValue::DescriptionDetails => vec![Token::DescriptionDetails(inner)],
            NodeValue::CodeBlock(ref block) => {
                let info = String::from_utf8(block.info.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8"))
                })?;
                let code = String::from_utf8(block.literal.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Codeblock contains invalid UTF-8"))
                })?;
                self.features.codeblock = true;
                vec![Token::CodeBlock(info, code)]
            }
            NodeValue::HtmlBlock(ref block) => {
                let text = String::from_utf8(block.literal.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8"))
                })?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            }
            NodeValue::HtmlInline(ref html) => {
                let text = String::from_utf8(html.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("HTML block contains invalid UTF-8"))
                })?;
                if self.html_as_text {
                    vec![Token::Str(text)]
                } else {
                    debug!("{}", lformat!("ignoring HTML block '{}'", text));
                    vec![]
                }
            }
            NodeValue::Paragraph => {
                if !self.ignore_paragraphs {
                    vec![Token::Paragraph(inner)]
                } else {
                    inner
                }
            }
            NodeValue::Heading(ref heading) => vec![Token::Header(heading.level as i32, inner)],
            NodeValue::ThematicBreak => vec![Token::Rule],
            NodeValue::FootnoteDefinition(ref def) => {
                let reference = String::from_utf8(def.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Footnote definition contains invalid UTF-8"),
                    )
                })?;
                vec![Token::FootnoteDefinition(reference, inner)]
            }
            NodeValue::Text(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Markdown file contains invalid UTF-8"),
                    )
                })?;
                vec![Token::Str(text)]
            }
            NodeValue::Code(ref text) => {
                let text = String::from_utf8(text.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Markdown file contains invalid UTF-8"),
                    )
                })?;
                vec![Token::Code(text)]
            }
            NodeValue::SoftBreak => vec![Token::SoftBreak],
            NodeValue::LineBreak => vec![Token::HardBreak],
            NodeValue::Emph => vec![Token::Emphasis(inner)],
            NodeValue::TaskItem(checked) => {
                self.features.taskitem = true;
                vec![Token::TaskItem(checked, inner)]
            },
            NodeValue::Strong => vec![Token::Strong(inner)],
            NodeValue::Strikethrough => {
                self.features.strikethrough = true;
                vec![Token::Strikethrough(inner)]
            }
            NodeValue::Superscript => vec![Token::Superscript(inner)],
            NodeValue::Link(ref link) => {
                self.features.url = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Link URL contains invalid UTF-8"))
                })?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Link title contains invalid UTF-8"))
                })?;
                vec![Token::Link(url, title, inner)]
            }
            NodeValue::Image(ref link) => {
                self.features.image = true;
                let url = String::from_utf8(link.url.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Image URL contains invalid UTF-8"))
                })?;
                let title = String::from_utf8(link.title.clone()).map_err(|_| {
                    Error::parser(&self.source, lformat!("Image title contains invalid UTF-8"))
                })?;
                vec![Token::Image(url, title, inner)]
            }
            NodeValue::FootnoteReference(ref name) => {
                let name = String::from_utf8(name.clone()).map_err(|_| {
                    Error::parser(
                        &self.source,
                        lformat!("Footnote reference contains invalid UTF-8"),
                    )
                })?;

                vec![Token::FootnoteReference(name)]
            }
            NodeValue::TableCell => vec![Token::TableCell(inner)],
            NodeValue::TableRow(header) => {
                if header {
                    vec![Token::TableHead(inner)]
                } else {
                    vec![Token::TableRow(inner)]
                }
            }
            NodeValue::Table(ref aligns) => {
                self.features.table = true;
                // TODO: actually use alignements)
                vec![Token::Table(aligns.len() as i32, inner)]
            }
        };
        Ok(inner)
    }
}

/// Replace consecutives Strs by a Str of both, collapse soft breaks to previous std and so on
fn collapse(ast: &mut Vec<Token>) {
    let mut i = 0;
    while i < ast.len() {
        if ast[i].is_str() && i + 1 < ast.len() {
            if ast[i + 1].is_str() {
                // Two consecutives Str, concatenate them
                let token = ast.remove(i + 1);
                if let (&mut Token::Str(ref mut dest), Token::Str(ref source)) =
                    (&mut ast[i], token)
                {
                    //                        dest.push(' ');
                    dest.push_str(source);
                    continue;
                } else {
                    unreachable!();
                }
            } else if ast[i + 1] == Token::SoftBreak {
                ast.remove(i + 1);
                if let &mut Token::Str(ref mut dest) = &mut ast[i] {
                    dest.push(' ');
                    continue;
                } else {
                    unreachable!();
                }
            }
        }

        // If token is containing others, recurse into them
        if let Some(ref mut inner) = ast[i].inner_mut() {
            collapse(inner);
        }
        i += 1;
    }
}

/// Replace images which are alone in a paragraph by standalone images
fn find_standalone(ast: &mut Vec<Token>) {
    for token in ast {
        let res = if let &mut Token::Paragraph(ref mut inner) = token {
            if inner.len() == 1 {
                if inner[0].is_image() {
                    if let Token::Image(source, title, inner) =
                        mem::replace(&mut inner[0], Token::Rule)
                    {
                        Token::StandaloneImage(source, title, inner)
                    } else {
                        unreachable!();
                    }
                } else {
                    // If paragraph only contains a link only containing an image, ok too
                    // Fixme: messy code and unnecessary clone
                    if let Token::Link(ref url, ref alt, ref mut inner) = inner[0] {
                        if inner[0].is_image() {
                            if let Token::Image(source, title, inner) =
                                mem::replace(&mut inner[0], Token::Rule)
                            {
                                Token::Link(
                                    url.clone(),
                                    alt.clone(),
                                    vec![Token::StandaloneImage(source, title, inner)],
                                )
                            } else {
                                unreachable!();
                            }
                        } else {
                            continue;
                        }
                    } else {
                        continue;
                    }
                }
            } else {
                continue;
            }
        } else {
            continue;
        };

        *token = res;
    }
}
<|endoftext|>


<commit_before>use state::State;
use traits::{FromLua, ToLua};
use status::{LuaStatus, LuaOk};

/**
 *  Proxy to Lua general functions.
 *
 *  The goal is to provide unified API in order to interact with Lua in a transparent way.
 */
pub struct Lua<'self>
{
    state: State<'self>,
}

impl<'self> Lua<'self>
{
    pub fn new() -> Lua
    {
        Lua {
            state: State::new(),
        }
    }

    /// Push a Rust value to the Lua stack.
    pub fn push<T: ToLua>(&self, val: T)
    {
        val.to_lua(&self.state);
    }

    /// Get a Rust value from the Lua stack at specified index.
    pub fn get<T: FromLua>(&self, idx: int) -> Option<T>
    {
        FromLua::from_lua(&self.state, idx)
    }

    /// Get a Rust value from call arguments.
    pub fn get_arg<T: FromLua>(&self, idx: int) -> Option<T>
    {
        // Incremented by one to match Lua indexing.
        self.get(State::upvalue_index(idx + 1))
    }

    /// Pop a Rust value from the Lua stack.
    pub fn pop<T: FromLua>(&self) -> Option<T>
    {
        let v = self.peek();
        self.state.pop(1);
        v
    }

    /// Peek a Rust value from the Lua stack.
    pub fn peek<T: FromLua>(&self) -> Option<T>
    {
        self.get(-1)
    }

    /// Get a Rust value from the Lua globals.
    pub fn get_global<T: FromLua>(&self, name: &str) -> Option<T>
    {
        self.state.get_global(name);
        self.get(-1)
    }

    /// Set a Rust value to the Lua globals.
    pub fn set_global<T: ToLua>(&self, name: &str, val: T)
    {
        self.push(val);
        self.state.set_global(name);
    }

    /// Execute a file then return a status.
    pub fn exec_file(&self, filename: &str) -> LuaStatus
    {
        match self.state.load_file(filename)
        {
            LuaOk => self.state.exec(),
            status => status,
        }
    }
}
<commit_msg>Add lua::Lua::exec_str method.<commit_after>use state::State;
use traits::{FromLua, ToLua};
use status::{LuaStatus, LuaOk};

/**
 *  Proxy to Lua general functions.
 *
 *  The goal is to provide unified API in order to interact with Lua in a transparent way.
 */
pub struct Lua<'self>
{
    state: State<'self>,
}

impl<'self> Lua<'self>
{
    pub fn new() -> Lua
    {
        Lua {
            state: State::new(),
        }
    }

    /// Push a Rust value to the Lua stack.
    pub fn push<T: ToLua>(&self, val: T)
    {
        val.to_lua(&self.state);
    }

    /// Get a Rust value from the Lua stack at specified index.
    pub fn get<T: FromLua>(&self, idx: int) -> Option<T>
    {
        FromLua::from_lua(&self.state, idx)
    }

    /// Get a Rust value from call arguments.
    pub fn get_arg<T: FromLua>(&self, idx: int) -> Option<T>
    {
        // Incremented by one to match Lua indexing.
        self.get(State::upvalue_index(idx + 1))
    }

    /// Pop a Rust value from the Lua stack.
    pub fn pop<T: FromLua>(&self) -> Option<T>
    {
        let v = self.peek();
        self.state.pop(1);
        v
    }

    /// Peek a Rust value from the Lua stack.
    pub fn peek<T: FromLua>(&self) -> Option<T>
    {
        self.get(-1)
    }

    /// Get a Rust value from the Lua globals.
    pub fn get_global<T: FromLua>(&self, name: &str) -> Option<T>
    {
        self.state.get_global(name);
        self.get(-1)
    }

    /// Set a Rust value to the Lua globals.
    pub fn set_global<T: ToLua>(&self, name: &str, val: T)
    {
        self.push(val);
        self.state.set_global(name);
    }

    /// Execute a file then return a status.
    pub fn exec_file(&self, filename: &str) -> LuaStatus
    {
        match self.state.load_file(filename)
        {
            LuaOk => self.state.exec(),
            status => status,
        }
    }

    /// Execute a string then return a status.
    pub fn exec_str(&self, source: &str) -> LuaStatus
    {
        match self.state.load_str(source)
        {
            LuaOk => self.state.exec(),
            status => status,
        }
    }
}
<|endoftext|>


<commit_before>#[link(name = "nss", vers = "0.0-pre")];

#[feature(struct_variant)];
#[feature(globs)];

extern mod nspr;

extern mod extra;

use std::rt::io::fs::{File};
use std::{os, ptr, vec, str};
use std::rt::io::{Reader, Writer, io_error};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};

use std::path::Path;
use std::libc::{c_void};
use std::unstable::atomics::{AtomicBool, Acquire, Release, INIT_ATOMIC_BOOL};

pub use raw::nss::*;
use nspr::raw::nspr::*;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

static mut NSS_INIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_INIT_END: AtomicBool = INIT_ATOMIC_BOOL;

static mut NSS_UNINIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_UNINIT_END: AtomicBool = INIT_ATOMIC_BOOL;

pub struct NSS {

    priv nss_ctx: Option<*c_void>,
    priv nss_cert_mod: Option<SECMODModule>,
    cfg_dir: Option<~str>,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None, cfg_dir: None,  }
}

pub fn set_cfg_dir(&mut self, cfg_dir: &str)
{
  self.cfg_dir = Some(cfg_dir.to_owned());
}

pub fn init(&mut self) -> SECStatus {
unsafe {
  if(NSS_IsInitialized() == PRTrue ) { return SECSuccess; }
  if NSS_INIT_START.swap(true, Acquire) { while !NSS_INIT_END.load(Release) { std::task::deschedule(); } }

  self.cfg_dir = match self.cfg_dir {
            None => Some(os::getenv("SSL_DIR").unwrap_or(format!("{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~"")).to_owned())),
            Some(ref s) => Some(s.to_owned()), };
  let cfg_dir = match self.cfg_dir {
            Some(ref s) => s.to_owned(),
            None => ~"", };
  let cfg_path = &Path::new(cfg_dir.clone());
  let nss_path = format!("sql:{}", cfg_dir);

  if(!cfg_path.exists()) {
          if(NSS_NoDB_Init(ptr::null()) == SECFailure){
                 fail!("NSS is borked!");
          }
     }
     else {
     nss_path.with_c_str(|nssdb| self.nss_ctx = Some(NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_READONLY | NSS_INIT_PK11RELOAD)));
     }

  do nss_cmd { NSS_SetDomesticPolicy() };
  self.nss_cert_mod = Some(*SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse));
  if(self.nss_cert_mod.unwrap().loaded != PRTrue)
  {
     return SECFailure;
  }
  NSS_INIT_END.store(true, Release);

  if(NSS_IsInitialized() == PRTrue) {
    SECSuccess
  }
  else {
    SECFailure
  }

 }
}

pub fn uninit(&mut self) -> SECStatus {
    unsafe {
    if(NSS_IsInitialized() == PRFalse) { return SECSuccess; }
    if NSS_UNINIT_START.swap(true, Acquire) { while !NSS_UNINIT_END.load(Release) { std::task::deschedule(); } }
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    if(!self.nss_ctx.is_none()) { NSS_ShutdownContext(self.nss_ctx.unwrap()) };
    self.nss_ctx = None;
    NSS_UNINIT_END.store(true, Release);
    }
    SECSuccess
}

pub fn trust_cert(file: ~str) -> SECStatus
{
    let path = &Path::new(file);
    let mut retStatus = SECFailure;
    if(!path.exists()){ return retStatus; }
    do io_error::cond.trap(|_| { retStatus = SECFailure; }).inside
    {
      unsafe
      {
        let pemdata = str::from_utf8_owned(File::open(path).read_to_end());
        let cert = CERT_DecodeCertFromPackage(pemdata.to_c_str().unwrap(), pemdata.to_c_str().len() as i32) ;
        let trust = CERTCertTrust { sslFlags: 0, emailFlags: 0, objectSigningFlags: 0 };
        CERT_DecodeTrustString(&trust, "TCu,Cu,Tu".to_c_str().unwrap());
        retStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
      }
    }
    retStatus
}

}
pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", get_nss_error());
    }
}

pub fn get_nss_error() -> ~str {
    unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl SSLStream {

pub fn connect(addr: SocketAddr, hostname: ~str) -> SSLStream
{
    unsafe {

    let oldmodel = PR_OpenTCPSocket(PR_AF_INET);
    let model = SSL_ImportFD(ptr::null(), oldmodel);
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_SSL2, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PRFalse) };
    let sslfd = PR_OpenTCPSocket(PR_AF_INET);
    PR_Connect(sslfd, &PRNetAddr { family: PR_AF_INET, ip: PR_htonl(IpAddrToBytes(addr.ip)), port: PR_htons(addr.port), pad: [0,0,0,0,0,0,0,0] }, 30000);
    let ssl_socket = SSL_ImportFD(model, sslfd);
    PR_Close(model);
    do nss_cmd { SSL_ResetHandshake(ssl_socket, PRFalse) };
    do nss_cmd { SSL_SetURL(ssl_socket, hostname.to_c_str().unwrap()) };
    do nss_cmd { SSL_ForceHandshake(ssl_socket) };

    SSLStream { sslfd: ssl_socket, is_eof: false }

    }
}

pub fn disconnect(&mut self) -> PRStatus {
        unsafe { PR_Close(self.sslfd) }
}

}

impl Reader for SSLStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
    match unsafe { PR_Read(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) } {
     0 => { self.is_eof = true; None },
     -1 => None,
     bytes_read => Some(bytes_read as uint)
    }
}
       fn eof(&mut self) -> bool {
            self.is_eof
       }
}

impl Writer for SSLStream {
    fn write(&mut self, buf: &[u8]) {
        unsafe { PR_Write(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) };
    }
    fn flush(&mut self) {
        //nop
    }
}

pub fn IpAddrToBytes(addr: IpAddr) -> u32 {
match addr {
        Ipv4Addr(o1, o2, o3, o4) => ((o1 as u32 << 24) + (o2 as u32 << 16) + (o3 as u32 << 8) + (o4 as u32 << 0)) as u32,
        _ => 0u32 }
}

<commit_msg>More robust nss database handling<commit_after>#[link(name = "nss", vers = "0.0-pre")];

#[feature(struct_variant)];
#[feature(globs)];

extern mod nspr;

extern mod extra;

use std::rt::io::fs::{File, mkdir_recursive};
use std::{os, ptr, vec, str};
use std::rt::io::{Reader, Writer, io_error};
use std::rt::io::net::ip::{SocketAddr, IpAddr, Ipv4Addr};

use std::path::Path;
use std::libc::{c_void};
use std::unstable::atomics::{AtomicBool, Acquire, Release, INIT_ATOMIC_BOOL};

pub use raw::nss::*;
use nspr::raw::nspr::*;

#[cfg(test)]
mod tests;

pub mod raw { pub mod nss; }

static mut NSS_INIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_INIT_END: AtomicBool = INIT_ATOMIC_BOOL;

static mut NSS_UNINIT_START: AtomicBool = INIT_ATOMIC_BOOL;
static mut NSS_UNINIT_END: AtomicBool = INIT_ATOMIC_BOOL;

pub struct NSS {

    priv nss_ctx: Option<*c_void>,
    priv nss_cert_mod: Option<SECMODModule>,
    cfg_dir: Option<~str>,
}

impl NSS {

pub fn new() -> NSS {
 NSS { nss_ctx: None, nss_cert_mod: None, cfg_dir: None,  }
}

pub fn set_cfg_dir(&mut self, cfg_dir: &str)
{
  self.cfg_dir = Some(cfg_dir.to_owned());
}

pub fn init(&mut self) -> SECStatus {
unsafe {
  if(NSS_IsInitialized() == PRTrue ) { return SECSuccess; }
  if NSS_INIT_START.swap(true, Acquire) { while !NSS_INIT_END.load(Release) { std::task::deschedule(); } }

  self.cfg_dir = match self.cfg_dir {
            None => Some(os::getenv("SSL_DIR").unwrap_or(format!("{}/.pki/nssdb", os::getenv("HOME").unwrap_or(~".")).to_owned())),
            Some(ref s) => Some(s.to_owned()), };
  let cfg_dir = match self.cfg_dir {
            Some(ref s) => s.to_owned(),
            None => ~"", };
  let mut cfg_path = Path::new(cfg_dir.clone());
  let mut nss_path = format!("sql:{}", cfg_dir);

  if(!cfg_path.exists()) {
          let system_path = &Path::new("/etc/pki/nssdb");
          if(!system_path.exists()) {
             do io_error::cond.trap(|_|{}).inside { mkdir_recursive(&cfg_path, 0b111_111_111); }
          }
          else {
            cfg_path = Path::new("/etc/pki/nssdb");
            nss_path = format!("sql:{}", system_path.as_str().unwrap());
          }
     }

     if(cfg_path.exists()) {
        nss_path.with_c_str(|nssdb| self.nss_ctx = Some(NSS_InitContext(nssdb, ptr::null(), ptr::null(), ptr::null(), ptr::null(), NSS_INIT_PK11RELOAD)));
     }

     if(NSS_IsInitialized() == PRFalse) {
                if(NSS_NoDB_Init(ptr::null()) == SECFailure){
                    fail!("NSS is borked!");
                }
     }

  do nss_cmd { NSS_SetDomesticPolicy() };
  self.nss_cert_mod = Some(*SECMOD_LoadUserModule("library=libnssckbi.so name=\"Root Certs\"".to_c_str().unwrap(),  ptr::null(), PRFalse));
  if(self.nss_cert_mod.unwrap().loaded != PRTrue) {
     return SECFailure;
  }
  NSS_INIT_END.store(true, Release);

  if(NSS_IsInitialized() == PRTrue) {
    SECSuccess
  }
  else {
    SECFailure
  }

 }
}

pub fn uninit(&mut self) -> SECStatus {
    unsafe {
    if(NSS_IsInitialized() == PRFalse) { return SECSuccess; }
    if NSS_UNINIT_START.swap(true, Acquire) { while !NSS_UNINIT_END.load(Release) { std::task::deschedule(); } }
    SECMOD_DestroyModule(&self.nss_cert_mod.unwrap());
    if(!self.nss_ctx.is_none()) { NSS_ShutdownContext(self.nss_ctx.unwrap()) };
    self.nss_ctx = None;
    NSS_UNINIT_END.store(true, Release);
    }
    SECSuccess
}

pub fn trust_cert(file: ~str) -> SECStatus
{
    let path = &Path::new(file);
    let mut retStatus = SECFailure;
    if(!path.exists()){ return retStatus; }
    do io_error::cond.trap(|_| { retStatus = SECFailure; }).inside
    {
      unsafe
      {
        let pemdata = str::from_utf8_owned(File::open(path).read_to_end());
        let cert = CERT_DecodeCertFromPackage(pemdata.to_c_str().unwrap(), pemdata.to_c_str().len() as i32);
        let trust = CERTCertTrust { sslFlags: 0, emailFlags: 0, objectSigningFlags: 0 };
        CERT_DecodeTrustString(&trust, "TCu,Cu,Tu".to_c_str().unwrap());
        retStatus = CERT_ChangeCertTrust(CERT_GetDefaultCertDB(), cert, &trust);
      }
    }
    retStatus
}

}
pub fn nss_cmd(blk: &fn() -> SECStatus) {
    let result = blk();
    if(result == SECFailure) {
      fail!("NSS Failed with {}", get_nss_error());
    }
}

pub fn get_nss_error() -> ~str {
    unsafe { std::str::raw::from_c_str(PR_ErrorToName(PR_GetError())) }
}

pub struct SSLStream {
    sslfd: *c_void,
    is_eof: bool,
}

impl SSLStream {

pub fn connect(addr: SocketAddr, hostname: ~str) -> SSLStream
{
    unsafe {

    let oldmodel = PR_OpenTCPSocket(PR_AF_INET);
    let model = SSL_ImportFD(ptr::null(), oldmodel);
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_SSL2, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_V2_COMPATIBLE_HELLO, PRFalse) };
    do nss_cmd { SSL_OptionSet(model, SSL_ENABLE_DEFLATE, PRFalse) };
    let sslfd = PR_OpenTCPSocket(PR_AF_INET);
    PR_Connect(sslfd, &PRNetAddr { family: PR_AF_INET, ip: PR_htonl(IpAddrToBytes(addr.ip)), port: PR_htons(addr.port), pad: [0,0,0,0,0,0,0,0] }, 30000);
    let ssl_socket = SSL_ImportFD(model, sslfd);
    PR_Close(model);
    do nss_cmd { SSL_ResetHandshake(ssl_socket, PRFalse) };
    do nss_cmd { SSL_SetURL(ssl_socket, hostname.to_c_str().unwrap()) };
    do nss_cmd { SSL_ForceHandshake(ssl_socket) };

    SSLStream { sslfd: ssl_socket, is_eof: false }

    }
}

pub fn disconnect(&mut self) -> PRStatus {
        unsafe { PR_Close(self.sslfd) }
}

}

impl Reader for SSLStream {
    fn read(&mut self, buf: &mut [u8]) -> Option<uint> {
    match unsafe { PR_Read(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) } {
     0 => { self.is_eof = true; None },
     -1 => None,
     bytes_read => Some(bytes_read as uint)
    }
}
       fn eof(&mut self) -> bool {
            self.is_eof
       }
}

impl Writer for SSLStream {
    fn write(&mut self, buf: &[u8]) {
        unsafe { PR_Write(self.sslfd, vec::raw::to_ptr(buf) as *c_void, buf.len() as i32) };
    }
    fn flush(&mut self) {
        //nop
    }
}

pub fn IpAddrToBytes(addr: IpAddr) -> u32 {
match addr {
        Ipv4Addr(o1, o2, o3, o4) => ((o1 as u32 << 24) + (o2 as u32 << 16) + (o3 as u32 << 8) + (o4 as u32 << 0)) as u32,
        _ => 0u32 }
}

<|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 = 8;
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>Thread count was too low.<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;

    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::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt::Result as FMTResult;
use std::result::Result;

use clap::ArgMatches;

use runtime::Runtime;

pub mod bm;
pub mod helpers;

pub trait Module<'a> : Debug {
    fn exec(&self, matches: &ArgMatches) -> bool;
    fn name(&self) -> &'static str;
}

<commit_msg>Add doc to Module trait<commit_after>use std::collections::HashMap;
use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt::Result as FMTResult;
use std::result::Result;

use clap::ArgMatches;

use runtime::Runtime;

pub mod bm;
pub mod helpers;

/**
 * Module interface, each module has to implement this.
 */
pub trait Module<'a> : Debug {
    fn exec(&self, matches: &ArgMatches) -> bool;
    fn name(&self) -> &'static str;
}

<|endoftext|>


<commit_before>extern crate rand;

use util::{TAU, PI};

pub enum Waveform {
    Sine,
    Sawtooth,
    Square,
    Noise,
}

pub struct Oscillator {
    sample_rate: f32,
    phase: f32,
    waveform: Waveform,
    frequency: f32,
}

impl Oscillator {
    pub fn new(sample_rate: f32) -> Oscillator {
        Oscillator {
            phase: 0.0,
            sample_rate: sample_rate,
            waveform: Waveform::Sine,
            frequency: 440f32,
        }
    }

    pub fn tick(&mut self) {
        self.phase = (self.phase + TAU * self.frequency / self.sample_rate) % TAU;
    }

    pub fn sample(&self) -> f32 {
        match self.waveform {
            Waveform::Sine => self.phase.sin(),
            Waveform::Sawtooth => self.phase / PI - 1.0f32,
            Waveform::Square => if self.phase < PI { -1f32 } else { 1f32 },
            Waveform::Noise => 2f32 * rand::random::<f32>() - 1f32,
        }
    }

    pub fn fill(&mut self, buffer: &mut[f32]) {
        for out_sample in buffer.iter_mut() {
            self.tick();
            *out_sample = self.sample();
        }
    }

    pub fn set_waveform(&mut self, waveform: Waveform) {
        self.waveform = waveform;
    }

    pub fn set_frequency(&mut self, freq: f32) {
        self.frequency = freq;
    }
}

impl Iterator for Oscillator {
    type Item = f32;

    fn next(&mut self) -> Option<f32> {
        self.tick();
        Some(self.sample())
    }
}
<commit_msg>replace oscillator frequency with norm_freq<commit_after>extern crate rand;

use util::{TAU, PI};

pub enum Waveform {
    Sine,
    Sawtooth,
    Square,
    Noise,
}

pub struct Oscillator {
    sample_rate: f32,
    phase: f32,
    waveform: Waveform,
    norm_freq: f32,
}

impl Oscillator {
    pub fn new(sample_rate: f32) -> Oscillator {
        Oscillator {
            phase: 0.0,
            sample_rate: sample_rate,
            waveform: Waveform::Sine,
            norm_freq: TAU * 440f32 / sample_rate,
        }
    }

    pub fn tick(&mut self) {
        self.phase = (self.phase + self.norm_freq) % TAU;
    }

    pub fn sample(&self) -> f32 {
        match self.waveform {
            Waveform::Sine => self.phase.sin(),
            Waveform::Sawtooth => self.phase / PI - 1.0f32,
            Waveform::Square => if self.phase < PI { -1f32 } else { 1f32 },
            Waveform::Noise => 2f32 * rand::random::<f32>() - 1f32,
        }
    }

    pub fn fill(&mut self, buffer: &mut[f32]) {
        for out_sample in buffer.iter_mut() {
            self.tick();
            *out_sample = self.sample();
        }
    }

    pub fn set_waveform(&mut self, waveform: Waveform) {
        self.waveform = waveform;
    }

    pub fn set_frequency(&mut self, freq: f32) {
        self.norm_freq = TAU * freq / self.sample_rate;
    }
}

impl Iterator for Oscillator {
    type Item = f32;

    fn next(&mut self) -> Option<f32> {
        self.tick();
        Some(self.sample())
    }
}
<|endoftext|>


<commit_before>use std::str::from_utf8;

use uuid::Uuid;

use super::sdk::SdkInfo;

#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MemDbHeader {
    pub version: u32,
    pub sdk_info: PackedSdkInfo,
    pub variants_start: u32,
    pub variants_count: u32,
    pub uuids_start: u32,
    pub uuids_count: u32,
    pub tagged_object_names_start: u32,
    pub tagged_object_names_end: u32,
    pub object_names_start: u32,
    pub object_names_count: u32,
    pub symbols_start: u32,
    pub symbols_count: u32,
}

#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct PackedSdkInfo {
    pub name: [u8; 8],
    pub version_major: u16,
    pub version_minor: u16,
    pub version_patchlevel: u16,
    pub build: [u8; 10],
    pub flavour: [u8; 16],
}

#[repr(C, packed)]
pub struct StoredSlice {
    pub offset: u32,
    pub len: u32,
}

#[repr(C, packed)]
pub struct IndexedUuid {
    pub uuid: Uuid,
    pub idx: u16,
}

#[repr(C, packed)]
#[derive(Debug)]
pub struct IndexItem {
    addr_low: u32,
    addr_high: u16,
    src_id: u16,
    sym_id: u32,
}

fn str_from_zero_slice(slice: &[u8]) -> &str {
    from_utf8(slice).unwrap().trim_right_matches('\x00')
}

impl PackedSdkInfo {

    pub fn set_from_sdk_info(&mut self, info: &SdkInfo) {
        self.version_major = info.version_major() as u16;
        self.version_minor = info.version_minor() as u16;
        self.version_patchlevel = info.version_patchlevel() as u16;
        (&mut self.name[..]).copy_from_slice(info.name().as_bytes());
        (&mut self.build[..]).copy_from_slice(info.build().as_bytes());
        (&mut self.flavour[..]).copy_from_slice(
            info.flavour().as_ref().map(|x| x.as_bytes()).unwrap_or(b""));
    }

    pub fn to_sdk_info(&self) -> SdkInfo {
        let flavour = str_from_zero_slice(&self.flavour[..]);
        SdkInfo::new(
            str_from_zero_slice(&self.name[..]),
            self.version_major as u32,
            self.version_minor as u32,
            self.version_patchlevel as u32,
            str_from_zero_slice(&self.build[..]),
            if flavour.len() == 0 { None } else { Some(flavour) },
        )
    }
}

impl IndexedUuid {

    pub fn new(uuid: &Uuid, idx: usize) -> IndexedUuid {
        IndexedUuid {
            uuid: *uuid,
            idx: idx as u16,
        }
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn idx(&self) -> usize {
        self.idx as usize
    }
}

impl StoredSlice {

    pub fn new(offset: usize, mut len: usize, is_compressed: bool) -> StoredSlice {
        if is_compressed {
            len |= 0x80000000;
        }
        StoredSlice {
            offset: offset as u32,
            len: len as u32,
        }
    }

    pub fn offset(&self) -> usize {
        self.offset as usize
    }

    pub fn len(&self) -> usize {
        (self.len as usize) & 0x7fffffff
    }

    pub fn is_compressed(&self) -> bool {
        self.len >> 31 != 0
    }
}

impl IndexItem {
    pub fn new(addr: u64, src_id: usize, sym_id: usize) -> IndexItem {
        IndexItem {
            addr_low: (addr & 0xffffffff) as u32,
            addr_high: ((addr >> 32) &0xffff) as u16,
            src_id: src_id as u16,
            sym_id: sym_id as u32,
        }
    }

    pub fn addr(&self) -> u64 {
        ((self.addr_high as u64) << 32) | (self.addr_low as u64)
    }

    pub fn src_id(&self) -> usize {
        self.src_id as usize
    }

    pub fn sym_id(&self) -> usize {
        self.sym_id as usize
    }
}
<commit_msg>Correctly slice a slice down<commit_after>use std::str::from_utf8;

use uuid::Uuid;

use super::sdk::SdkInfo;

#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct MemDbHeader {
    pub version: u32,
    pub sdk_info: PackedSdkInfo,
    pub variants_start: u32,
    pub variants_count: u32,
    pub uuids_start: u32,
    pub uuids_count: u32,
    pub tagged_object_names_start: u32,
    pub tagged_object_names_end: u32,
    pub object_names_start: u32,
    pub object_names_count: u32,
    pub symbols_start: u32,
    pub symbols_count: u32,
}

#[repr(C, packed)]
#[derive(Default, Copy, Clone)]
pub struct PackedSdkInfo {
    pub name: [u8; 8],
    pub version_major: u16,
    pub version_minor: u16,
    pub version_patchlevel: u16,
    pub build: [u8; 10],
    pub flavour: [u8; 16],
}

#[repr(C, packed)]
pub struct StoredSlice {
    pub offset: u32,
    pub len: u32,
}

#[repr(C, packed)]
pub struct IndexedUuid {
    pub uuid: Uuid,
    pub idx: u16,
}

#[repr(C, packed)]
#[derive(Debug)]
pub struct IndexItem {
    addr_low: u32,
    addr_high: u16,
    src_id: u16,
    sym_id: u32,
}

fn copy_str_to_slice(slice: &mut [u8], s: &str) {
    let bytes = s.as_bytes();
    (&mut slice[..bytes.len()]).copy_from_slice(bytes);
}

fn str_from_zero_slice(slice: &[u8]) -> &str {
    from_utf8(slice).unwrap().trim_right_matches('\x00')
}

impl PackedSdkInfo {

    pub fn set_from_sdk_info(&mut self, info: &SdkInfo) {
        self.version_major = info.version_major() as u16;
        self.version_minor = info.version_minor() as u16;
        self.version_patchlevel = info.version_patchlevel() as u16;
        copy_str_to_slice(&mut self.name[..], info.name());
        copy_str_to_slice(&mut self.build[..], info.build());
        copy_str_to_slice(&mut self.build[..],
            info.flavour().as_ref().unwrap_or(&""));
    }

    pub fn to_sdk_info(&self) -> SdkInfo {
        let flavour = str_from_zero_slice(&self.flavour[..]);
        SdkInfo::new(
            str_from_zero_slice(&self.name[..]),
            self.version_major as u32,
            self.version_minor as u32,
            self.version_patchlevel as u32,
            str_from_zero_slice(&self.build[..]),
            if flavour.len() == 0 { None } else { Some(flavour) },
        )
    }
}

impl IndexedUuid {

    pub fn new(uuid: &Uuid, idx: usize) -> IndexedUuid {
        IndexedUuid {
            uuid: *uuid,
            idx: idx as u16,
        }
    }

    pub fn uuid(&self) -> &Uuid {
        &self.uuid
    }

    pub fn idx(&self) -> usize {
        self.idx as usize
    }
}

impl StoredSlice {

    pub fn new(offset: usize, mut len: usize, is_compressed: bool) -> StoredSlice {
        if is_compressed {
            len |= 0x80000000;
        }
        StoredSlice {
            offset: offset as u32,
            len: len as u32,
        }
    }

    pub fn offset(&self) -> usize {
        self.offset as usize
    }

    pub fn len(&self) -> usize {
        (self.len as usize) & 0x7fffffff
    }

    pub fn is_compressed(&self) -> bool {
        self.len >> 31 != 0
    }
}

impl IndexItem {
    pub fn new(addr: u64, src_id: usize, sym_id: usize) -> IndexItem {
        IndexItem {
            addr_low: (addr & 0xffffffff) as u32,
            addr_high: ((addr >> 32) &0xffff) as u16,
            src_id: src_id as u16,
            sym_id: sym_id as u32,
        }
    }

    pub fn addr(&self) -> u64 {
        ((self.addr_high as u64) << 32) | (self.addr_low as u64)
    }

    pub fn src_id(&self) -> usize {
        self.src_id as usize
    }

    pub fn sym_id(&self) -> usize {
        self.sym_id as usize
    }
}
<|endoftext|>


<commit_before>#[repr(C)]
pub struct MemoryMapTag {
    typ: u32,
    size: u32,
    entry_size: u32,
    entry_version: u32,
    first_area: MemoryArea,
}

impl MemoryMapTag {
    pub fn memory_areas(&self) -> MemoryAreaIter {
        let self_ptr = self as *const MemoryMapTag;
        let start_area = (&self.first_area) as *const MemoryArea;
        MemoryAreaIter {
            current_area: start_area,
            last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64)
                as *const MemoryArea,
            entry_size: self.entry_size,
        }
    }
}

#[repr(C)]
pub struct MemoryArea {
    pub base_addr: u64,
    pub length: u64,
    typ: u32,
    _reserved: u32,
}

#[derive(Clone)]
pub struct MemoryAreaIter {
    current_area: *const MemoryArea,
    last_area: *const MemoryArea,
    entry_size: u32,
}

impl Iterator for MemoryAreaIter {
    type Item = &'static MemoryArea;
    fn next(&mut self) -> Option<&'static MemoryArea> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*self.current_area};
            self.current_area = ((self.current_area as u64) + self.entry_size as u64)
                as *const MemoryArea;
            if area.typ == 1 {
                Some(area)
            } else {self.next()}
        }
    }
}
<commit_msg>Add `#[derive(Debug)]` on all public memory map structs<commit_after>#[derive(Debug)]
#[repr(C)]
pub struct MemoryMapTag {
    typ: u32,
    size: u32,
    entry_size: u32,
    entry_version: u32,
    first_area: MemoryArea,
}

impl MemoryMapTag {
    pub fn memory_areas(&self) -> MemoryAreaIter {
        let self_ptr = self as *const MemoryMapTag;
        let start_area = (&self.first_area) as *const MemoryArea;
        MemoryAreaIter {
            current_area: start_area,
            last_area: (self_ptr as u64 + (self.size - self.entry_size) as u64)
                as *const MemoryArea,
            entry_size: self.entry_size,
        }
    }
}

#[derive(Debug)]
#[repr(C)]
pub struct MemoryArea {
    pub base_addr: u64,
    pub length: u64,
    typ: u32,
    _reserved: u32,
}

#[derive(Clone, Debug)]
pub struct MemoryAreaIter {
    current_area: *const MemoryArea,
    last_area: *const MemoryArea,
    entry_size: u32,
}

impl Iterator for MemoryAreaIter {
    type Item = &'static MemoryArea;
    fn next(&mut self) -> Option<&'static MemoryArea> {
        if self.current_area > self.last_area {
            None
        } else {
            let area = unsafe{&*self.current_area};
            self.current_area = ((self.current_area as u64) + self.entry_size as u64)
                as *const MemoryArea;
            if area.typ == 1 {
                Some(area)
            } else {self.next()}
        }
    }
}
<|endoftext|>