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

use std::iter;
use std::mem;
use std::ptr::{null, null_mut};

use libc::{c_void, size_t};
use libc::funcs::c95::stdlib::{free, malloc};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: *mut Node,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: *mut Node,
    /// Pointer to a possibly free node in the pool.
    next: *mut Node,
    /// Size of the memory pool.
    size: u32,
}

/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: *mut Node, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: Option<&Vec<[*mut Node; 2]>>,
                        maxbits: i32,
                        pool: &mut NodePool)
                        -> *mut Node {
    loop {
        if pool.next >= pool.nodes.offset(pool.size as isize) {
            // Garbage collection
            for i in 0..pool.size {
                (*pool.nodes.offset(i as isize)).in_use = false;
            }
            if let Some(lists) = lists {
                for i in 0..maxbits * 2 {
                    let mut node = lists[(i / 2) as usize][(i % 2) as usize];
                    while !node.is_null() {
                        (*node).in_use = true;
                        node = (*node).tail;
                    }
                }
            }
            pool.next = pool.nodes;
        }
        if !(*pool.next).in_use {
            break;
        }
        pool.next = pool.next.offset(1);
    }
    let free_node = pool.next;
    pool.next = pool.next.offset(1);
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: &mut Vec<[*mut Node; 2]>,
                      maxbits: i32,
                      leaves: &[Node],
                      numsymbols: i32,
                      pool: &mut NodePool,
                      index: i32,
                      is_final: bool) {
    let lastcount = (*lists[index as usize][1]).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(Some(&lists), maxbits, pool);
    let oldchain = lists[index as usize][1];

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    lists[index as usize][0] = oldchain;
    lists[index as usize][1] = newchain;

    if index == 0 {
        // New leaf node in list 0.
        init_node(leaves[lastcount as usize].weight,
                  lastcount + 1,
                  null_mut(),
                  newchain);
    } else {
        let sum = (*lists[(index - 1) as usize][0]).weight +
                  (*lists[(index - 1) as usize][1]).weight;
        if lastcount < numsymbols && sum > leaves[lastcount as usize].weight {
            // New leaf inserted in list, so count is incremented.
            init_node(leaves[lastcount as usize].weight,
                      lastcount + 1,
                      (*oldchain).tail,
                      newchain);
        } else {
            init_node(sum,
                      lastcount,
                      lists[(index - 1) as usize][1],
                      newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: &mut NodePool,
                     leaves: &[Node],
                     maxbits: i32) -> Vec<[*mut Node; 2]> {
    let node0 = get_free_node(None, maxbits, pool);
    let node1 = get_free_node(None, maxbits, pool);
    init_node(leaves[0].weight, 1, null_mut(), node0);
    init_node(leaves[1].weight, 2, null_mut(), node1);
    iter::repeat([node0, node1]).take(maxbits as usize).collect()
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: *const Node, leaves: &[Node], bitlengths: *mut u32) {
    let mut node = chain;
    while node != null() {
        for i in 0..(*node).count {
            *bitlengths.offset(leaves[i as usize].count as isize) =
                *bitlengths.offset(leaves[i as usize].count as isize) + 1;
        }
        node = (*node).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
extern "C" fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    unsafe {
        let node_a: *const Node = a as *const Node;
        let node_b: *const Node = b as *const Node;
        (*node_a).weight as i32 - (*node_b).weight as i32
    }
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void,
             nmemb: size_t,
             size: size_t,
             compar: extern "C" fn(*const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: *const usize,
                                          n: i32,
                                          maxbits: i32,
                                          bitlengths: *mut u32)
                                          -> bool {
    // One leaf per symbol. Only numsymbols leaves will be used.
    let mut leaves: Vec<Node> = Vec::with_capacity(n as usize);

    // Initialize all bitlengths at 0.
    for i in 0..n {
        *bitlengths.offset(i as isize) = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if *frequencies.offset(i as isize) != 0 {
            leaves.push(Node {
                weight: *frequencies.offset(i as isize),
                count: i, // Index of symbol this leaf represents.
                tail: null_mut(),
                in_use: false,
            });
        }
    }
    // Amount of symbols with frequency > 0.
    let numsymbols = leaves.len();

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        *bitlengths.offset(leaves[0].count as isize) = 1;
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves.as_mut_ptr() as *mut c_void,
          numsymbols as size_t,
          mem::size_of::<Node>() as size_t,
          leaf_comparator);

    // Initialize node memory pool.
    let pool_size = 2 * maxbits * (maxbits + 1);
    let pool_nodes = malloc((pool_size as usize * mem::size_of::<Node>()) as size_t) as *mut Node;
    let mut pool = NodePool {
        size: pool_size as u32,
        nodes: pool_nodes,
        next: pool_nodes,
    };
    for i in 0..pool.size {
        (*pool.nodes.offset(i as isize)).in_use = false;
    }

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let mut lists: Vec<[*mut Node; 2]> = init_lists(&mut pool, &leaves, maxbits);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(&mut lists,
                    maxbits,
                    &leaves,
                    numsymbols as i32,
                    &mut pool,
                    maxbits - 1,
                    is_final);
    }

    extract_bit_lengths(lists[maxbits as usize - 1][1], &leaves, bitlengths);
    free(pool.nodes as *mut c_void);
    false // OK.
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;
    use libc::{c_void, size_t};

    use super::qsort;

    extern "C" fn comparator(a: *const c_void, b: *const c_void) -> i32 {
        unsafe { *(a as *const i32) - *(b as *const i32) }
    }

    #[test]
    fn test_qsort() {
        unsafe {
            let mut a: [i32; 5] = [3, 2, 4, 1, 5];
            qsort(a.as_mut_ptr() as *mut c_void,
                  a.len() as size_t,
                  size_of::<i32>() as size_t,
                  comparator);
            assert_eq!(a, [1, 2, 3, 4, 5]);
        }
    }
}
<commit_msg>Remove malloc from katajainen<commit_after>//! Bounded package merge algorithm, based on the paper
//! "A Fast and Space-Economical Algorithm for Length-Limited Coding
//! Jyrki Katajainen, Alistair Moffat, Andrew Turpin".

use std::iter;
use std::mem;
use std::ptr::{null, null_mut};

use libc::{c_void, size_t};

/// Nodes forming chains. Also used to represent leaves.
struct Node {
    /// Total weight (symbol count) of this chain.
    weight: usize,
    /// Previous node(s) of this chain, or 0 if none.
    tail: *mut Node,
    /// Leaf symbol index, or number of leaves before this chain.
    count: i32,
    /// Tracking for garbage collection.
    in_use: bool,
}

/// Memory pool for nodes.
struct NodePool {
    /// The pool.
    nodes: Vec<Node>,
    /// Index of a possibly free node in the pool.
    next: u32,
    /// Size of the memory pool.
    size: u32,
}

impl NodePool {
    fn new(pool_size: u32) -> NodePool {
        NodePool {
            nodes: (0..pool_size).map(|_| {
                Node {
                    weight: 0,
                    tail: null_mut(),
                    count: 0,
                    in_use: false,
                }
            }).collect(),
            next: 0,
            size: pool_size,
        }
    }
}
/// Initializes a chain node with the given values and marks it as in use.
unsafe fn init_node(weight: usize, count: i32, tail: *mut Node, node: *mut Node) {
    (*node).weight = weight;
    (*node).count = count;
    (*node).tail = tail;
    (*node).in_use = true;
}

/**
 * Finds a free location in the memory pool. Performs garbage collection if needed.
 * lists: If given, used to mark in-use nodes during garbage collection.
 * maxbits: Size of lists.
 * pool: Memory pool to get free node from.
 */
unsafe fn get_free_node(lists: Option<&Vec<[*mut Node; 2]>>,
                        maxbits: i32,
                        pool: &mut NodePool)
                        -> *mut Node {
    loop {
        if pool.next >= pool.size {
            // Garbage collection
            for i in 0..pool.size {
                pool.nodes[i as usize].in_use = false;
            }
            if let Some(lists) = lists {
                for i in 0..maxbits * 2 {
                    let mut node = lists[(i / 2) as usize][(i % 2) as usize];
                    while !node.is_null() {
                        (*node).in_use = true;
                        node = (*node).tail;
                    }
                }
            }
            pool.next = 0;
        }
        if !pool.nodes[pool.next as usize].in_use {
            break;
        }
        pool.next += 1;
    }
    let free_node = &mut pool.nodes[pool.next as usize];
    pool.next += 1;
    free_node
}

/**
 * Performs a Boundary Package-Merge step. Puts a new chain in the given list. The
 * new chain is, depending on the weights, a leaf or a combination of two chains
 * from the previous list.
 * lists: The lists of chains.
 * maxbits: Number of lists.
 * leaves: The leaves, one per symbol.
 * numsymbols: Number of leaves.
 * pool: the node memory pool.
 * index: The index of the list in which a new chain or leaf is required.
 * final: Whether this is the last time this function is called. If it is then it
 *   is no more needed to recursively call self.
 */
unsafe fn boundary_pm(lists: &mut Vec<[*mut Node; 2]>,
                      maxbits: i32,
                      leaves: &[Node],
                      numsymbols: i32,
                      pool: &mut NodePool,
                      index: i32,
                      is_final: bool) {
    let lastcount = (*lists[index as usize][1]).count; // Count of last chain of list.

    if index == 0 && lastcount >= numsymbols {
        return;
    }

    let newchain = get_free_node(Some(&lists), maxbits, pool);
    let oldchain = lists[index as usize][1];

    // These are set up before the recursive calls below, so that there is a list
    // pointing to the new node, to let the garbage collection know it's in use.
    lists[index as usize][0] = oldchain;
    lists[index as usize][1] = newchain;

    if index == 0 {
        // New leaf node in list 0.
        init_node(leaves[lastcount as usize].weight,
                  lastcount + 1,
                  null_mut(),
                  newchain);
    } else {
        let sum = (*lists[(index - 1) as usize][0]).weight +
                  (*lists[(index - 1) as usize][1]).weight;
        if lastcount < numsymbols && sum > leaves[lastcount as usize].weight {
            // New leaf inserted in list, so count is incremented.
            init_node(leaves[lastcount as usize].weight,
                      lastcount + 1,
                      (*oldchain).tail,
                      newchain);
        } else {
            init_node(sum,
                      lastcount,
                      lists[(index - 1) as usize][1],
                      newchain);
            if !is_final {
                // Two lookahead chains of previous list used up, create new ones.
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
                boundary_pm(lists, maxbits, leaves, numsymbols, pool, index - 1, false);
            }
        }
    }
}

/// Initializes each list with as lookahead chains the two leaves with lowest weights.
unsafe fn init_lists(pool: &mut NodePool,
                     leaves: &[Node],
                     maxbits: i32) -> Vec<[*mut Node; 2]> {
    let node0 = get_free_node(None, maxbits, pool);
    let node1 = get_free_node(None, maxbits, pool);
    init_node(leaves[0].weight, 1, null_mut(), node0);
    init_node(leaves[1].weight, 2, null_mut(), node1);
    iter::repeat([node0, node1]).take(maxbits as usize).collect()
}

/**
 * Converts result of boundary package-merge to the bitlengths. The result in the
 * last chain of the last list contains the amount of active leaves in each list.
 * chain: Chain to extract the bit length from (last chain from last list).
 */
unsafe fn extract_bit_lengths(chain: *const Node, leaves: &[Node], bitlengths: *mut u32) {
    let mut node = chain;
    while node != null() {
        for i in 0..(*node).count {
            *bitlengths.offset(leaves[i as usize].count as isize) =
                *bitlengths.offset(leaves[i as usize].count as isize) + 1;
        }
        node = (*node).tail;
    }
}

/// Comparator for sorting the leaves. Has the function signature for qsort.
extern "C" fn leaf_comparator(a: *const c_void, b: *const c_void) -> i32 {
    unsafe {
        let node_a: *const Node = a as *const Node;
        let node_b: *const Node = b as *const Node;
        (*node_a).weight as i32 - (*node_b).weight as i32
    }
}

#[link(name="c")]
extern {
    fn qsort(base: *mut c_void,
             nmemb: size_t,
             size: size_t,
             compar: extern "C" fn(*const c_void, *const c_void) -> i32);
}

pub unsafe fn length_limited_code_lengths(frequencies: *const usize,
                                          n: i32,
                                          maxbits: i32,
                                          bitlengths: *mut u32)
                                          -> bool {
    // One leaf per symbol. Only numsymbols leaves will be used.
    let mut leaves: Vec<Node> = Vec::with_capacity(n as usize);

    // Initialize all bitlengths at 0.
    for i in 0..n {
        *bitlengths.offset(i as isize) = 0;
    }

    // Count used symbols and place them in the leaves.
    for i in 0..n {
        if *frequencies.offset(i as isize) != 0 {
            leaves.push(Node {
                weight: *frequencies.offset(i as isize),
                count: i, // Index of symbol this leaf represents.
                tail: null_mut(),
                in_use: false,
            });
        }
    }
    // Amount of symbols with frequency > 0.
    let numsymbols = leaves.len();

    // Check special cases and error conditions.
    if (1 << maxbits) < numsymbols {
        return true; // Error, too few maxbits to represent symbols.
    }
    if numsymbols == 0 {
        return false; // No symbols at all. OK.
    }
    if numsymbols == 1 {
        *bitlengths.offset(leaves[0].count as isize) = 1;
        return false; // Only one symbol, give it bitlength 1, not 0. OK.
    }

    // Sort the leaves from lightest to heaviest.
    qsort(leaves.as_mut_ptr() as *mut c_void,
          numsymbols as size_t,
          mem::size_of::<Node>() as size_t,
          leaf_comparator);

    // Initialize node memory pool.
    let mut pool = NodePool::new(2 * maxbits as u32 * (maxbits as u32 + 1));

    // Array of lists of chains. Each list requires only two lookahead chains at
    // a time, so each list is a array of two Node*'s.
    let mut lists: Vec<[*mut Node; 2]> = init_lists(&mut pool, &leaves, maxbits);

    // In the last list, 2 * numsymbols - 2 active chains need to be created. Two
    // are already created in the initialization. Each BoundaryPM run creates one.
    let num_boundary_pm_runs = 2 * numsymbols - 4;
    for i in 0..num_boundary_pm_runs {
        let is_final = i == num_boundary_pm_runs - 1;
        boundary_pm(&mut lists,
                    maxbits,
                    &leaves,
                    numsymbols as i32,
                    &mut pool,
                    maxbits - 1,
                    is_final);
    }

    extract_bit_lengths(lists[maxbits as usize - 1][1], &leaves, bitlengths);
    false // OK.
}

#[cfg(test)]
mod tests {
    use std::mem::size_of;
    use libc::{c_void, size_t};

    use super::qsort;

    extern "C" fn comparator(a: *const c_void, b: *const c_void) -> i32 {
        unsafe { *(a as *const i32) - *(b as *const i32) }
    }

    #[test]
    fn test_qsort() {
        unsafe {
            let mut a: [i32; 5] = [3, 2, 4, 1, 5];
            qsort(a.as_mut_ptr() as *mut c_void,
                  a.len() as size_t,
                  size_of::<i32>() as size_t,
                  comparator);
            assert_eq!(a, [1, 2, 3, 4, 5]);
        }
    }
}
<|endoftext|>


<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 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.
pub 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(),
        }
    }

    pub fn buckets(&self) -> &Vec<KBucket<TId, TAddr>> {
        &self.buckets
    }

    #[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()
    }

    pub fn data(&self) -> &VecDeque<Node<TId, TAddr>> {
        &self.data
    }
    pub fn size(&self) -> usize {
        self.size
    }

    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);
        let mut lengths = vec![0; n.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)));
        lengths[0] = 1;
        lengths[1] = 2;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);

        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        lengths[1] = 1;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);
        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));
    }
}
<commit_msg>Fix node finding algorithm.<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.
pub 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(),
        }
    }

    pub fn buckets(&self) -> &Vec<KBucket<TId, TAddr>> {
        &self.buckets
    }

    #[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 mut data_copy: Vec<_> = self.buckets.iter().flat_map(|b| &b.data).map(|n| n.clone()).collect();
        data_copy.sort_by_key(|n| KNodeTable::<TId, TAddr>::distance(id, &n.id));
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    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 mut data_copy: Vec<_> = self.data.iter().map(|n| n.clone()).collect();
        data_copy.sort_by_key(|n| KNodeTable::<TId, TAddr>::distance(id, &n.id));
        data_copy[0..cmp::min(count, data_copy.len())].to_vec()
    }

    pub fn data(&self) -> &VecDeque<Node<TId, TAddr>> {
        &self.data
    }
    pub fn size(&self) -> usize {
        self.size
    }

    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);
        let mut lengths = vec![0; n.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)));
        lengths[0] = 1;
        lengths[1] = 2;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);

        let nodes = n.pop_oldest();
        assert_eq!(1, nodes.len());
        assert_eq!(test::make_id(41), nodes[0].id);
        lengths[1] = 1;
        assert_eq!(n.buckets().iter().map(|b| b.data.len()).collect::<Vec<_>>(), lengths);
        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 mut n = KNodeTable::new(id1);
        n.update(&test::new_node(id2));
    }

    #[test]
    fn test_nodetable_find_closest() {
        let mut n = KNodeTable::new(test::make_id(0b0000));
        let node1 = test::new_node(test::make_id(0b0101));
        let node2 = test::new_node(test::make_id(0b1010));
        let node3 = test::new_node(test::make_id(0b1110));
        assert!(n.update(&node1));
        assert!(n.update(&node2));
        assert!(n.update(&node3));
        assert_node_list_eq(&vec![&node3], &n.find(&test::make_id(0b1111), 1));
        assert_node_list_eq(&vec![&node2], &n.find(&test::make_id(0b1011), 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();
        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!()
}
<commit_msg>Remove unwraps in alloc error 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();
        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!()
}

#[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>// lib/option::rs

tag t<@T> { none; some(T); }

fn get<@T>(opt: t<T>) -> T {
    alt opt { some(x) { x } none. { fail "option none" } }
}

fn map<@T, @U>(f: block(T) -> U, opt: t<T>) -> t<U> {
    alt opt { some(x) { some(f(x)) } none. { none } }
}

fn is_none<@T>(opt: t<T>) -> bool {
    alt opt { none. { true } some(_) { false } }
}

fn is_some<@T>(opt: t<T>) -> bool { !is_none(opt) }

fn from_maybe<@T>(def: T, opt: t<T>) -> T {
    alt opt { some(x) { x } none. { def } }
}

fn maybe<@T, @U>(def: U, f: block(T) -> U, opt: t<T>) -> U {
    alt opt { none. { def } some(t) { f(t) } }
}

// Can be defined in terms of the above when/if we have const bind.
fn may<@T>(f: block(T), opt: t<T>) {
    alt opt { none. {/* nothing */ } some(t) { f(t); } }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Make option::get return the option contents by reference<commit_after>// lib/option::rs

tag t<@T> { none; some(T); }

fn get<@T>(opt: t<T>) -> &T {
    alt opt { some(x) { ret x; } none. { fail "option none"; } }
}

fn map<@T, @U>(f: block(T) -> U, opt: t<T>) -> t<U> {
    alt opt { some(x) { some(f(x)) } none. { none } }
}

fn is_none<@T>(opt: t<T>) -> bool {
    alt opt { none. { true } some(_) { false } }
}

fn is_some<@T>(opt: t<T>) -> bool { !is_none(opt) }

fn from_maybe<@T>(def: T, opt: t<T>) -> T {
    alt opt { some(x) { x } none. { def } }
}

fn maybe<@T, @U>(def: U, f: block(T) -> U, opt: t<T>) -> U {
    alt opt { none. { def } some(t) { f(t) } }
}

// Can be defined in terms of the above when/if we have const bind.
fn may<@T>(f: block(T), opt: t<T>) {
    alt opt { none. {/* nothing */ } some(t) { f(t); } }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::Gc;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::codemap;
use syntax::parse::token;

fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span) -> (Gc<ast::Expr>, Gc<ast::Expr>) {
    (cx.expr_uint(span, 0), cx.expr_uint(span, 0))
}

/// `generate()` method generating code
fn method_generate(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure) -> Gc<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let mut statements = Vec::new();
            let id_at = cx.ident_of("at");
            statements.push(cx.stmt_let(
                span,
                true,
                id_at,
                cx.expr_call(span, cx.expr_vec_ng(span), Vec::new())
                ));
            let ex_stride = cx.expr_uint(span, 0);  //TODO
            let mut offset = 0u;    //TODO
            for (def, &(ident, _)) in definition.fields.iter().zip(fields.iter()) {
                let (ex_count, ex_type) = decode_type(cx, span);
                let ex_struct = cx.expr_struct(span,
                    cx.path(span, vec![cx.ident_of("gfx"), cx.ident_of("Attribute")]),
                    vec![
                        cx.field_imm(span, cx.ident_of("buffer"), substr.nonself_args[1]),
                        cx.field_imm(span, cx.ident_of("elem_count"), ex_count),
                        cx.field_imm(span, cx.ident_of("elem_type"), ex_type),
                        cx.field_imm(span, cx.ident_of("offset"), cx.expr_uint(span, offset)),
                        cx.field_imm(span, cx.ident_of("stride"), ex_stride),
                        cx.field_imm(span, cx.ident_of("name"), cx.expr_method_call(span,
                            cx.expr_str(span, token::get_ident(ident)),
                            cx.ident_of("to_string"), Vec::new()))
                    ]
                );
                statements.push(cx.stmt_expr(cx.expr_method_call(
                    span,
                    cx.expr_ident(span, id_at),
                    cx.ident_of("push"),
                    vec![ex_struct]
                    )));
            }
            cx.expr_block(cx.block_all(span, Vec::new(), statements, None))
        },
        _ => {
            cx.span_err(span, "Unable to implement `generate()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// Decorator for `vertex_format` attribute
pub fn expand_vertex_format(context: &mut ext::base::ExtCtxt, span: codemap::Span,
                            meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
                            push: |Gc<ast::Item>|) {
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "VertexFormat"],
            lifetime: None,
            params: Vec::new(),
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "generate",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![box generic::ty::Self],
                        global: false,
                    }),
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "BufferHandle"]
                    )),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Vec"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec!["gfx", "Attribute"])),
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(method_generate),
            },
        ],
    };
    trait_def.expand(context, meta_item, item, push);
}
<commit_msg>Mesh macro - Partially implemented type decoding, improved general structure.<commit_after>// Copyright 2014 The Gfx-rs Developers.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::gc::Gc;
use syntax::{ast, ext};
use syntax::ext::build::AstBuilder;
use syntax::ext::deriving::generic;
use syntax::codemap;
use syntax::parse::token;

fn decode_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, ty: &str) -> Gc<ast::Expr> {
    cx.expr_lit(span, ast::LitIntUnsuffixed(0))
}

fn decode_count_type(cx: &mut ext::base::ExtCtxt, span: codemap::Span, ty: &ast::Ty_) -> (Gc<ast::Expr>, Gc<ast::Expr>) {
    let (count, etype) = match *ty {
        ast::TyPath(ref p, _, _) => (1, decode_type(cx, span, p.segments[0].identifier.name.as_str())),
        ast::TyFixedLengthVec(pty, expr) => {
            let t = match pty.node {
                ast::TyPath(ref p, _, _) => decode_type(cx, span, p.segments[0].identifier.name.as_str()),
                _ => {
                    cx.span_err(span, format!(
                        "Unsupported fixed vector sub-type: {}",
                        pty.node).as_slice()
                    );
                    cx.expr_lit(span, ast::LitNil)
                },
            };
            let c = match expr.node {
                ast::ExprLit(plit) => match plit.node {
                    ast::LitIntUnsuffixed(value) => value,
                    _ => {
                        cx.span_err(span, format!(
                            "Unsupported vector size literal: {}",
                            plit.node).as_slice()
                        );
                        0
                    },
                },
                _ => {
                    cx.span_err(span, format!(
                        "Unsupported vector size: {}",
                        expr.node).as_slice()
                    );
                    0
                },
            };
            (c, t)
        },
        _ => {
            cx.span_err(span, format!(
                "Unsupported attribute type: {}",
                ty).as_slice()
            );
            (0, cx.expr_lit(span, ast::LitNil))
        },
    };
    (cx.expr_lit(span, ast::LitIntUnsuffixed(count)), etype)
}

/// `generate()` method generating code
fn method_generate(cx: &mut ext::base::ExtCtxt, span: codemap::Span,
                   substr: &generic::Substructure) -> Gc<ast::Expr> {
    match *substr.fields {
        generic::StaticStruct(ref definition, generic::Named(ref fields)) => {
            let mut statements = Vec::new();
            let id_at = cx.ident_of("at");
            statements.push(cx.stmt_let(span, true, id_at, cx.expr_vec_ng(span)));
            let ex_offset = cx.expr_lit(span, ast::LitIntUnsuffixed(0));    //TODO
            let ex_stride = cx.expr_cast(span,
                cx.expr_call(span,
                    cx.expr_path(cx.path_all(
                        span,
                        true,
                        vec![
                            cx.ident_of("std"),
                            cx.ident_of("mem"),
                            cx.ident_of("size_of")
                        ],
                        Vec::new(),
                        vec![cx.ty_ident(span, substr.type_ident)]
                    )),
                    Vec::new()
                ),
                cx.ty_path(cx.path_global(span, vec![
                    cx.ident_of("gfx"),
                    cx.ident_of("attrib"),
                    cx.ident_of("Stride")
                    ]), None)
            );
            for (def, &(ident, _)) in definition.fields.iter().zip(fields.iter()) {
                let (ex_count, ex_type) = decode_count_type(cx, span, &def.node.ty.node);
                let ex_struct = cx.expr_struct(span,
                    cx.path(span, vec![
                        cx.ident_of("gfx"),
                        cx.ident_of("mesh"),
                        cx.ident_of("Attribute")
                        ]),
                    vec![
                        cx.field_imm(span, cx.ident_of("buffer"), substr.nonself_args[1]),
                        cx.field_imm(span, cx.ident_of("elem_count"), ex_count),
                        cx.field_imm(span, cx.ident_of("elem_type"), ex_type),
                        cx.field_imm(span, cx.ident_of("offset"), ex_offset),
                        cx.field_imm(span, cx.ident_of("stride"), ex_stride),
                        cx.field_imm(span, cx.ident_of("name"), cx.expr_method_call(span,
                            cx.expr_str(span, token::get_ident(ident)),
                            cx.ident_of("to_string"), Vec::new()))
                    ]
                );
                statements.push(cx.stmt_expr(cx.expr_method_call(
                    span,
                    cx.expr_ident(span, id_at),
                    cx.ident_of("push"),
                    vec![ex_struct]
                    )));
            }
            cx.expr_block(cx.block_all(
                span,
                Vec::new(),
                statements,
                Some(cx.expr_ident(span, id_at))
                ))
        },
        _ => {
            cx.span_err(span, "Unable to implement `generate()` on a non-structure");
            cx.expr_lit(span, ast::LitNil)
        }
    }
}

/// Decorator for `vertex_format` attribute
pub fn expand_vertex_format(context: &mut ext::base::ExtCtxt, span: codemap::Span,
                            meta_item: Gc<ast::MetaItem>, item: Gc<ast::Item>,
                            push: |Gc<ast::Item>|) {
    let trait_def = generic::TraitDef {
        span: span,
        attributes: Vec::new(),
        path: generic::ty::Path {
            path: vec!["gfx", "mesh", "VertexFormat"],
            lifetime: None,
            params: Vec::new(),
            global: true,
        },
        additional_bounds: Vec::new(),
        generics: generic::ty::LifetimeBounds::empty(),
        methods: vec![
            generic::MethodDef {
                name: "generate",
                generics: generic::ty::LifetimeBounds::empty(),
                explicit_self: None,
                args: vec![
                    generic::ty::Literal(generic::ty::Path {
                        path: vec!["Option"],
                        lifetime: None,
                        params: vec![box generic::ty::Self],
                        global: false,
                    }),
                    generic::ty::Literal(generic::ty::Path::new(
                        vec!["gfx", "BufferHandle"]
                    )),
                ],
                ret_ty: generic::ty::Literal(
                    generic::ty::Path {
                        path: vec!["Vec"],
                        lifetime: None,
                        params: vec![
                            box generic::ty::Literal(generic::ty::Path::new(
                                vec!["gfx", "mesh", "Attribute"])),
                        ],
                        global: false,
                    },
                ),
                attributes: Vec::new(),
                combine_substructure: generic::combine_substructure(method_generate),
            },
        ],
    };
    trait_def.expand(context, meta_item, item, push);
}
<|endoftext|>


<commit_before>use std::io::UserRWX;
use std::io::fs;
use std::io::process::{Command,ProcessOutput};
use std::io::{File,Truncate,Write};
use std::os;

pub fn mkdir(path: &Path)  {
    match fs::mkdir_recursive(path, UserRWX) {
        Err(_) => {},
        Ok(_) => {},
    }
}

pub fn read(path: &Path) -> Result<String, String> {
    match File::open(path) {
        Err(_) => Err(format!("couldn't open {}", path.display())),
        Ok(mut file) => match file.read_to_string() {
            Err(_) => Err(format!("couldn't read {}", path.display())),
            Ok(string) => Ok(string),
        }
    }
}

pub fn run(prefix: &str, id: &str, src: &str) -> Result<String, String> {
    let cwd = os::getcwd();
    let out_dir = cwd.join(format!("bin/{}/{}", prefix, id));

    let mut cmd = Command::new("rustc");
    cmd.cwd(&Path::new(format!("examples/{}/{}", prefix, id)));
    cmd.arg(format!("{}.rs", src));
    cmd.arg("--out-dir");
    cmd.arg(out_dir);

    match cmd.output() {
        Err(_) => return Err(format!("couldn't find rustc")),
        Ok(p) => if !p.status.success() {
            return Ok(String::from_utf8(p.error).unwrap());
        },
    }

    let executable = Path::new(format!("./bin/{}/{}/{}", prefix, id, src));

    match Command::new(&executable).output() {
        Err(_) => Err(format!("couldn't find {}", executable.display())),
        Ok(ProcessOutput { error: error, output: output, status: status }) => {
            let mut s = String::from_utf8(output).unwrap();
            if !status.success() {
                s.push_str(String::from_utf8(error).unwrap().as_slice());
            }

            Ok(s)
        }
    }
}

pub fn write(path: &Path, string: &str) -> Result<(), String> {
    match File::open_mode(path, Truncate, Write) {
        Err(_) => Err(format!("couldn't open {}", path.display())),
        Ok(mut file) => match file.write_str(string) {
            Err(_) => Err(format!("couldn't write {}", path.display())),
            Ok(_) => Ok(()),
        }
    }
}
<commit_msg>Update file.rs<commit_after>use std::io::UserRWX;
use std::io::fs;
use std::io::process::{Command,ProcessOutput};
use std::io::{File,Truncate,Write};
use std::os;

pub fn mkdir(path: &Path) {
    match fs::mkdir_recursive(path, UserRWX) {
        Err(_) => {},
        Ok(_) => {},
    }
}

pub fn read(path: &Path) -> Result<String, String> {
    match File::open(path) {
        Err(_) => Err(format!("couldn't open {}", path.display())),
        Ok(mut file) => match file.read_to_string() {
            Err(_) => Err(format!("couldn't read {}", path.display())),
            Ok(string) => Ok(string),
        }
    }
}

pub fn run(prefix: &str, id: &str, src: &str) -> Result<String, String> {
    let cwd = os::getcwd();
    let out_dir = cwd.join(format!("bin/{}/{}", prefix, id));

    let mut cmd = Command::new("rustc");
    cmd.cwd(&Path::new(format!("examples/{}/{}", prefix, id)));
    cmd.arg(format!("{}.rs", src));
    cmd.arg("--out-dir");
    cmd.arg(out_dir);

    match cmd.output() {
        Err(_) => return Err(format!("couldn't find rustc")),
        Ok(p) => if !p.status.success() {
            return Ok(String::from_utf8(p.error).unwrap());
        },
    }

    let executable = Path::new(format!("./bin/{}/{}/{}", prefix, id, src));

    match Command::new(&executable).output() {
        Err(_) => Err(format!("couldn't find {}", executable.display())),
        Ok(ProcessOutput { error: error, output: output, status: status }) => {
            let mut s = String::from_utf8(output).unwrap();
            if !status.success() {
                s.push_str(String::from_utf8(error).unwrap().as_slice());
            }

            Ok(s)
        }
    }
}

pub fn write(path: &Path, string: &str) -> Result<(), String> {
    match File::open_mode(path, Truncate, Write) {
        Err(_) => Err(format!("couldn't open {}", path.display())),
        Ok(mut file) => match file.write_str(string) {
            Err(_) => Err(format!("couldn't write {}", path.display())),
            Ok(_) => Ok(()),
        }
    }
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::any::Any;
use std::cell::RefCell;
use std::panic::{UnwindSafe, catch_unwind, resume_unwind};

thread_local!(static PANIC_RESULT: RefCell<Option<Box<Any + Send>>> = RefCell::new(None));

/// If there is a pending panic, resume unwinding.
pub fn maybe_resume_unwind() {
    if let Some(error) = PANIC_RESULT.with(|result| result.borrow_mut().take()) {
        resume_unwind(error);
    }
}

/// Generic wrapper for JS engine callbacks panic-catching
pub fn wrap_panic<F, R>(function: F, generic_return_type: R) -> R
    where F: FnMut() -> R + UnwindSafe
{
    let result = catch_unwind(function);
    match result {
        Ok(result) => result,
        Err(error) => {
            PANIC_RESULT.with(|result| {
                assert!(result.borrow().is_none());
                *result.borrow_mut() = Some(error);
            });
            generic_return_type
        }
    }
}
<commit_msg>Use a less strict bound for wrap_panic.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::any::Any;
use std::cell::RefCell;
use std::panic::{UnwindSafe, catch_unwind, resume_unwind};

thread_local!(static PANIC_RESULT: RefCell<Option<Box<Any + Send>>> = RefCell::new(None));

/// If there is a pending panic, resume unwinding.
pub fn maybe_resume_unwind() {
    if let Some(error) = PANIC_RESULT.with(|result| result.borrow_mut().take()) {
        resume_unwind(error);
    }
}

/// Generic wrapper for JS engine callbacks panic-catching
pub fn wrap_panic<F, R>(function: F, generic_return_type: R) -> R
    where F: FnOnce() -> R + UnwindSafe
{
    let result = catch_unwind(function);
    match result {
        Ok(result) => result,
        Err(error) => {
            PANIC_RESULT.with(|result| {
                assert!(result.borrow().is_none());
                *result.borrow_mut() = Some(error);
            });
            generic_return_type
        }
    }
}
<|endoftext|>


<commit_before>//! This module provides a trait `HasParam` which allows
//! to access the value of parameters in Gurobi environment object.

extern crate gurobi_sys as ffi;

// re-exports
pub use ffi::{IntParam, DoubleParam, StringParam};
pub use ffi::IntParam::*;
pub use ffi::DoubleParam::*;
pub use ffi::StringParam::*;

use std::ffi::CString;
use error::{Error, Result};
use util;

/// Provides general C API related to GRBenv.
pub trait HasEnvAPI {
  unsafe fn get_env(&self) -> *mut ffi::GRBenv;
  fn get_error_msg(&self) -> String;
}

/// Provides C APIs and some utility functions related to parameter access.
pub trait HasParamAPI<Output> {
  type RawFrom;
  type RawTo;
  type Init;

  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: Self::RawFrom)
                      -> ffi::c_int;

  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: Self::RawTo)
                      -> ffi::c_int;

  fn init() -> Self::Init;
  fn as_rawfrom(val: &mut Self::Init) -> Self::RawFrom;
  fn as_rawto(output: Output) -> Self::RawTo;
  fn to_out(init: Self::Init) -> Output;
}

/// provides function to query/set the value of parameters.
pub trait HasParam<P, Output>: HasEnvAPI
  where CString: From<P>,
        P: HasParamAPI<Output>
{
  /// Query the value of a parameter.
  fn get(&self, param: P) -> Result<Output> {
    let mut value = P::init();
    let error = unsafe {
      P::get_param(self.get_env(),
                   CString::from(param).as_ptr(),
                   P::as_rawfrom(&mut value))
    };
    if error != 0 {
      return Err(Error::FromAPI(self.get_error_msg(), error));
    }
    Ok(P::to_out(value))
  }

  /// Set the value of a parameter.
  fn set(&mut self, param: P, value: Output) -> Result<()> {
    let error = unsafe {
      P::set_param(self.get_env(),
                   CString::from(param).as_ptr(),
                   P::as_rawto(value))
    };
    if error != 0 {
      return Err(Error::FromAPI(self.get_error_msg(), error));
    }
    Ok(())
  }
}

impl HasParamAPI<i32> for IntParam {
  type Init = i32;
  type RawFrom = *mut ffi::c_int;
  type RawTo = ffi::c_int;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_int)
                      -> ffi::c_int {
    ffi::GRBgetintparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: ffi::c_int)
                      -> ffi::c_int {
    ffi::GRBsetintparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> i32 {
    0
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut i32) -> *mut ffi::c_int {
    val
  }

  #[inline(always)]
  fn as_rawto(output: i32) -> ffi::c_int {
    output
  }

  #[inline(always)]
  fn to_out(input: i32) -> i32 {
    input
  }
}

impl HasParamAPI<f64> for DoubleParam {
  type Init = f64;
  type RawFrom = *mut ffi::c_double;
  type RawTo = ffi::c_double;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_double)
                      -> ffi::c_int {
    ffi::GRBgetdblparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: ffi::c_double)
                      -> ffi::c_int {
    ffi::GRBsetdblparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> f64 {
    0.0
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut f64) -> *mut ffi::c_double {
    val
  }

  #[inline(always)]
  fn as_rawto(output: f64) -> ffi::c_double {
    output
  }

  #[inline(always)]
  fn to_out(input: f64) -> f64 {
    input
  }
}

impl HasParamAPI<String> for StringParam {
  type Init = Vec<ffi::c_char>;
  type RawFrom = *mut ffi::c_char;
  type RawTo = *const ffi::c_char;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_char)
                      -> ffi::c_int {
    ffi::GRBgetstrparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *const ffi::c_char)
                      -> ffi::c_int {
    ffi::GRBsetstrparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> Vec<ffi::c_char> {
    Vec::with_capacity(4096)
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut Vec<ffi::c_char>) -> *mut ffi::c_char {
    val.as_mut_ptr()
  }

  #[inline(always)]
  fn as_rawto(output: String) -> *const ffi::c_char {
    CString::new(output.as_str()).unwrap().as_ptr()
  }

  #[inline(always)]
  fn to_out(input: Vec<ffi::c_char>) -> String {
    unsafe { util::from_c_str(input.as_ptr()) }
  }
}
<commit_msg>fix doc<commit_after>extern crate gurobi_sys as ffi;

// re-exports
pub use ffi::{IntParam, DoubleParam, StringParam};
pub use ffi::IntParam::*;
pub use ffi::DoubleParam::*;
pub use ffi::StringParam::*;

use std::ffi::CString;
use error::{Error, Result};
use util;

/// Provides general C API related to GRBenv.
pub trait HasEnvAPI {
  unsafe fn get_env(&self) -> *mut ffi::GRBenv;
  fn get_error_msg(&self) -> String;
}

/// Provides C APIs and some utility functions related to parameter access.
pub trait HasParamAPI<Output> {
  type RawFrom;
  type RawTo;
  type Init;

  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: Self::RawFrom)
                      -> ffi::c_int;

  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: Self::RawTo)
                      -> ffi::c_int;

  fn init() -> Self::Init;
  fn as_rawfrom(val: &mut Self::Init) -> Self::RawFrom;
  fn as_rawto(output: Output) -> Self::RawTo;
  fn to_out(init: Self::Init) -> Output;
}

/// provides function to query/set the value of parameters.
pub trait HasParam<P, Output>: HasEnvAPI
  where CString: From<P>,
        P: HasParamAPI<Output>
{
  /// Query the value of a parameter.
  fn get(&self, param: P) -> Result<Output> {
    let mut value = P::init();
    let error = unsafe {
      P::get_param(self.get_env(),
                   CString::from(param).as_ptr(),
                   P::as_rawfrom(&mut value))
    };
    if error != 0 {
      return Err(Error::FromAPI(self.get_error_msg(), error));
    }
    Ok(P::to_out(value))
  }

  /// Set the value of a parameter.
  fn set(&mut self, param: P, value: Output) -> Result<()> {
    let error = unsafe {
      P::set_param(self.get_env(),
                   CString::from(param).as_ptr(),
                   P::as_rawto(value))
    };
    if error != 0 {
      return Err(Error::FromAPI(self.get_error_msg(), error));
    }
    Ok(())
  }
}

impl HasParamAPI<i32> for IntParam {
  type Init = i32;
  type RawFrom = *mut ffi::c_int;
  type RawTo = ffi::c_int;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_int)
                      -> ffi::c_int {
    ffi::GRBgetintparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: ffi::c_int)
                      -> ffi::c_int {
    ffi::GRBsetintparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> i32 {
    0
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut i32) -> *mut ffi::c_int {
    val
  }

  #[inline(always)]
  fn as_rawto(output: i32) -> ffi::c_int {
    output
  }

  #[inline(always)]
  fn to_out(input: i32) -> i32 {
    input
  }
}

impl HasParamAPI<f64> for DoubleParam {
  type Init = f64;
  type RawFrom = *mut ffi::c_double;
  type RawTo = ffi::c_double;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_double)
                      -> ffi::c_int {
    ffi::GRBgetdblparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: ffi::c_double)
                      -> ffi::c_int {
    ffi::GRBsetdblparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> f64 {
    0.0
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut f64) -> *mut ffi::c_double {
    val
  }

  #[inline(always)]
  fn as_rawto(output: f64) -> ffi::c_double {
    output
  }

  #[inline(always)]
  fn to_out(input: f64) -> f64 {
    input
  }
}

impl HasParamAPI<String> for StringParam {
  type Init = Vec<ffi::c_char>;
  type RawFrom = *mut ffi::c_char;
  type RawTo = *const ffi::c_char;

  #[inline(always)]
  unsafe fn get_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *mut ffi::c_char)
                      -> ffi::c_int {
    ffi::GRBgetstrparam(env, paramname, value)
  }

  #[inline(always)]
  unsafe fn set_param(env: *mut ffi::GRBenv,
                      paramname: ffi::c_str,
                      value: *const ffi::c_char)
                      -> ffi::c_int {
    ffi::GRBsetstrparam(env, paramname, value)
  }

  #[inline(always)]
  fn init() -> Vec<ffi::c_char> {
    Vec::with_capacity(4096)
  }

  #[inline(always)]
  fn as_rawfrom(val: &mut Vec<ffi::c_char>) -> *mut ffi::c_char {
    val.as_mut_ptr()
  }

  #[inline(always)]
  fn as_rawto(output: String) -> *const ffi::c_char {
    CString::new(output.as_str()).unwrap().as_ptr()
  }

  #[inline(always)]
  fn to_out(input: Vec<ffi::c_char>) -> String {
    unsafe { util::from_c_str(input.as_ptr()) }
  }
}
<|endoftext|>