<commit_before>use hash::KEY_SIZE;
use hash::Hash160;
use std::net;
use std::collections::VecDeque;
use std::mem;

const K : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Kademlia routing table, with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// can be resolved later.
pub struct RoutingTable {
   parent_key : Hash160,
   buckets    : Vec<Bucket>,
   conflicts  : Vec<EvictionConflict>,
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
#[derive(Debug, Clone)]
struct Bucket {
   entries  : VecDeque<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

#[derive(Debug, Clone, PartialEq)]
pub struct NodeInfo {
   pub key  : Hash160,
   pub ip   : net::IpAddr,
   pub port : u16,
}

#[derive(Debug, PartialEq)]
pub enum LookupResult {
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
   Myself,
}

impl RoutingTable {
   pub fn new(parent_key : Hash160) -> RoutingTable {
      let mut buckets = Vec::<Bucket>::with_capacity(KEY_SIZE);
      for _ in 0..KEY_SIZE {
         buckets.push(Bucket::new());
      }

      RoutingTable {
         parent_key : parent_key,
         buckets : buckets,
         conflicts  : Vec::new()
      }
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&mut self, info : NodeInfo) {
      if let Some(index) = self.bucket_for_node(&info.key) {
         let bucket = &mut self.buckets[index];
         bucket.entries.retain(|ref stored_info| info.key != stored_info.key);
         if bucket.entries.len() == BUCKET_DEPTH {
            let conflict = EvictionConflict {
               evicted  : bucket.entries.pop_front().unwrap(),
               inserted : info.clone()
            };
            self.conflicts.push(conflict);
         }
         bucket.entries.push_back(info);
      }
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   pub fn lookup(&self, key : &Hash160, n : usize) -> LookupResult {
      if *key == self.parent_key {
         return LookupResult::Myself;
      }

      match self.specific_node(key) {
         Some(info) => LookupResult::Found(info),
         None => LookupResult::ClosestNodes(self.closest_n_nodes_to(key, n)),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   fn specific_node(&self, key : &Hash160) -> Option<NodeInfo> {
      if let Some(index) = self.bucket_for_node(key){
         let bucket = &self.buckets[index];
         return bucket.entries.iter().find(|ref info| *key == info.key).cloned();
      }
      None
   }

   fn closest_n_nodes_to(&self, key : &Hash160, n : usize) -> Vec<NodeInfo>{
      let mut closest = Vec::with_capacity(n);
      let mut master_key = key ^ &self.parent_key;
      let ideal_bucket = master_key.height().unwrap();
      let mut floor = ideal_bucket;
      let mut ceiling = floor + 1;

      while ceiling > 1 {
         println!("Trying buckets {} to {}", floor, ceiling);
         for bucket_index in floor..ceiling {
            print!(" doot");
            let mut nodes_from_bucket = self.buckets[bucket_index].clone().entries.into_iter().collect::<Vec<NodeInfo>>();
            nodes_from_bucket.sort_by_key(|ref info| &info.key ^ key);
            let space_left = closest.capacity() - closest.len();
            nodes_from_bucket.truncate(space_left);
            closest.append(&mut nodes_from_bucket);
            if closest.capacity() == closest.len() {
               break;
            }
         }
         ceiling = floor;
         master_key.flip_bit(floor);
         floor = match master_key.height() {
            Some(height) => height,
            None => 1
         }
      }

      // If the master key algorithm wasn't enough, just pour from the higher buckets
      for bucket_index in (ideal_bucket+1)..KEY_SIZE {
         if closest.capacity() == closest.len() {
            break;
         }
         let mut nodes_from_bucket = self.buckets[bucket_index].clone().entries.into_iter().collect::<Vec<NodeInfo>>();
         nodes_from_bucket.sort_by_key(|ref info| &info.key ^ key);
         let space_left = closest.capacity() - closest.len();
         nodes_from_bucket.truncate(space_left);
         closest.append(&mut nodes_from_bucket);
      }
      closest
   }

   /// Returns the appropriate position for a node, by computing
   /// the last bit of their distance set to 1. None if we are
   /// attempting to add the parent key.
   fn bucket_for_node(&self, key : &Hash160) -> Option<usize> {
       (&self.parent_key ^ key).height()
   }

   fn revert_conflict(&mut self, conflict : EvictionConflict) {
      if let Some(index) = self.bucket_for_node(&conflict.inserted.key) {
         let bucket  = &mut self.buckets[index];
         let evictor = &mut bucket.entries.iter_mut().find(|ref info| conflict.inserted.key == info.key).unwrap();
         mem::replace::<NodeInfo>(evictor, conflict.evicted);
      }
   }
}

impl Bucket {
   pub fn new() -> Bucket {
      Bucket { entries : VecDeque::<NodeInfo>::with_capacity(BUCKET_DEPTH) }
   }
}

#[cfg(test)]
mod tests {
    use super::*;
    use hash::Hash160;
    use std::net;
    use std::str::FromStr;

    #[test]
    fn new_routing_table_is_empty() {
       let parent_key = Hash160::random();
       let table = RoutingTable::new(parent_key);
       let test_hash = Hash160::random();

       assert!(table.specific_node(&test_hash).is_none());
    }

    #[test]
    fn inserting_and_retrieving_specific_node() {
       let node_info = NodeInfo {
          key  : Hash160::random(),
          ip   : net::IpAddr::from_str("0.0.0.0").unwrap(),
          port : 50000
       };

       let mut table = RoutingTable::new(Hash160::random());
       table.insert_node(node_info.clone());
       assert_eq!(table.specific_node(&node_info.key), Some(node_info));
    }

    impl RoutingTable {
       pub fn fill_bucket(&mut self, bucket_index : usize, fill_quantity : u8) {
          // Otherwise this helper function becomes quite complex.
          assert!(bucket_index > 7);
          let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();
          for i in 0..fill_quantity {
             let mut key = self.parent_key.clone();
             key.flip_bit(bucket_index);

             key.raw[0] = i as u8;
             let info = NodeInfo {
                key  : key,
                ip   : any_ip.clone(),
                port : 0
             };
             self.insert_node(info);
          }
       }
    }

    #[test]
    fn inserting_in_a_full_bucket_causes_eviction_conflict() {
       let mut parent_key = Hash160::blank();
       parent_key.raw[1] = 1; // This will guarantee all nodes will fall on the same bucket.
       let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();

       let mut table = RoutingTable::new(parent_key);

       table.fill_bucket(8, super::BUCKET_DEPTH as u8);
       assert!(table.conflicts.is_empty());

       // When we add another node to the same bucket, we cause a conflict.
       let mut key = Hash160::blank();
       key.raw[0] = 0xFF;
       let info = NodeInfo {
          key  : key,
          ip   : any_ip.clone(),
          port : 0
       };
       table.insert_node(info);
       assert_eq!(table.conflicts.len(), 1);

       let conflict = table.conflicts.first().unwrap();
       // We evicted the oldest node, which has a blank key.
       assert!(table.specific_node(&conflict.inserted.key).is_some());
    }

    #[test]
    fn reverting_an_eviction_conflict_reinserts_the_evicted_node_in_place_of_evictor() {
       let mut parent_key = Hash160::blank();
       parent_key.raw[1] = 1; // This will guarantee all nodes will fall on the same bucket.
       let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();

       let mut table = RoutingTable::new(parent_key);

       table.fill_bucket(8, super::BUCKET_DEPTH as u8);
       assert!(table.conflicts.is_empty());

       // When we add another node to the same bucket, we cause a conflict.
       let mut key = Hash160::blank();
       key.raw[0] = 0xFF;
       let info = NodeInfo {
          key  : key,
          ip   : any_ip.clone(),
          port : 0
       };
       table.insert_node(info);
       assert_eq!(table.conflicts.len(), 1);
       let conflict = table.conflicts.pop().unwrap();

       table.revert_conflict(conflict.clone());
       // The evictor has been removed.
       assert!(table.specific_node(&conflict.inserted.key).is_none());
       // And the evicted has been reinserted.
       assert!(table.specific_node(&conflict.evicted.key).is_some());
    }

    #[test]
    fn lookup_for_a_stored_node() {
       let mut table = RoutingTable::new(Hash160::random());
       let node = NodeInfo {
          key  : Hash160::random(),
          ip   : net::IpAddr::from_str("0.0.0.0").unwrap(),
          port : 0,
       };
       table.insert_node(node.clone());

       assert_eq!(table.lookup(&node.key, 20), LookupResult::Found(node));
    }

    #[test]
    fn lookup_for_self() {
       let parent_key = Hash160::random();
       let table = RoutingTable::new(parent_key.clone());
       assert_eq!(table.lookup(&parent_key, 20), LookupResult::Myself);
    }

    #[test]
    fn ascending_lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(8); // Bucket 8
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }

    #[test]
    fn descending_lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(51); // Bucket 51
       node_key.raw[0] = 0xFF;
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }

    #[test]
    fn lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(25); // Bucket 25
       node_key.raw[0] = 0xFF;
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }

    #[test]
    fn lookup_on_a_randomized_table() {
       let mut table = RoutingTable::new(Hash160::random());
       let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();
       for _ in 0..100 {
          table.insert_node(NodeInfo {
             key  : Hash160::random(),
             ip   : any_ip.clone(),
             port : 0
          });
       }

       let node_key = Hash160::random();
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key, 30) {
          assert_eq!(nodes.len(), 30);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("You should go play the lottery...");
       }
    }

}
<commit_msg>WIP ordering algo<commit_after>use hash::KEY_SIZE;
use hash::Hash160;
use std::net;
use std::collections::VecDeque;
use std::mem;

const K : usize = 20;
const BUCKET_DEPTH : usize = K;

/// Kademlia routing table, with 160 buckets of `BUCKET_DEPTH` (k) node
/// identifiers each.
///
/// The structure employs least-recently seen eviction. Conflicts generated
/// by evicting a node by inserting a newer one remain tracked, so they can
/// be resolved later.
pub struct RoutingTable {
   parent_key : Hash160,
   buckets    : Vec<Bucket>,
   conflicts  : Vec<EvictionConflict>,
}

/// Bucket size is estimated to be small enough not to warrant
/// the downsides of using a linked list.
#[derive(Debug, Clone)]
struct Bucket {
   entries  : VecDeque<NodeInfo>,
}

/// Represents a conflict derived from attempting to insert a node in a full
/// bucket.
#[derive(Debug,Clone)]
struct EvictionConflict {
   evicted  : NodeInfo,
   inserted : NodeInfo
}

#[derive(Debug, Clone, PartialEq)]
pub struct NodeInfo {
   pub key  : Hash160,
   pub ip   : net::IpAddr,
   pub port : u16,
}

#[derive(Debug, PartialEq)]
pub enum LookupResult {
   Found(NodeInfo),
   ClosestNodes(Vec<NodeInfo>),
   Myself,
}

pub struct MasterKey {
   distance     : Hash160,
   floor        : usize,
   ceiling      : usize,
   initial      : usize,
}

impl MasterKey {
   fn new(distance : Hash160) -> MasterKey {
      MasterKey {
         distance : distance,
         initial  : distance.height().unwrap(),
         floor    : initial,
         ceiling  : initial + 1
      }
   }
}

impl Iterator for MasterKey {
//   type Item = usize;
//
//   fn next(&mut self) -> Option<usize> {
//      if floor == KEY_SIZE {
//         None
//      }
//      else if ceiling - floor > 0 {
//         let ret = Some(floor)
//         floor += 1;
//         ret
//      } else {
//         ceiling -= 1;
//         master_key.flip_bit(floor);
//
//         match master_key.height() {
//            Some(height) => floor = height,
//            None => { floor =
//         }
//      }
//   }
}

impl RoutingTable {
   pub fn new(parent_key : Hash160) -> RoutingTable {
      let mut buckets = Vec::<Bucket>::with_capacity(KEY_SIZE);
      for _ in 0..KEY_SIZE {
         buckets.push(Bucket::new());
      }

      RoutingTable {
         parent_key : parent_key,
         buckets : buckets,
         conflicts  : Vec::new()
      }
   }

   /// Inserts a node in the routing table. Employs least-recently-seen eviction
   /// by kicking out the oldest node in case the bucket is full, and registering
   /// an eviction conflict that can be revised later.
   pub fn insert_node(&mut self, info : NodeInfo) {
      if let Some(index) = self.bucket_for_node(&info.key) {
         let bucket = &mut self.buckets[index];
         bucket.entries.retain(|ref stored_info| info.key != stored_info.key);
         if bucket.entries.len() == BUCKET_DEPTH {
            let conflict = EvictionConflict {
               evicted  : bucket.entries.pop_front().unwrap(),
               inserted : info.clone()
            };
            self.conflicts.push(conflict);
         }
         bucket.entries.push_back(info);
      }
   }

   /// Performs a node lookup on the routing table. The lookup result may
   /// contain the specific node, a list of up to the N closest nodes, or
   /// report that the parent node itself was requested.
   pub fn lookup(&self, key : &Hash160, n : usize) -> LookupResult {
      if *key == self.parent_key {
         return LookupResult::Myself;
      }

      match self.specific_node(key) {
         Some(info) => LookupResult::Found(info),
         None => LookupResult::ClosestNodes(self.closest_n_nodes_to(key, n)),
      }
   }

   /// Returns a table entry for the specific node with a given hash.
   fn specific_node(&self, key : &Hash160) -> Option<NodeInfo> {
      if let Some(index) = self.bucket_for_node(key){
         let bucket = &self.buckets[index];
         return bucket.entries.iter().find(|ref info| *key == info.key).cloned();
      }
      None
   }

   fn closest_n_nodes_to(&self, key : &Hash160, n : usize) -> Vec<NodeInfo>{
      let mut closest = Vec::with_capacity(n);
      let mut master_key = key ^ &self.parent_key;
      let ideal_bucket = master_key.height().unwrap();
      let mut floor = ideal_bucket;
      let mut ceiling = floor + 1;

      while ceiling > 1 {
         for bucket_index in floor..ceiling {
            let mut nodes_from_bucket = self.buckets[bucket_index].clone().entries.into_iter().collect::<Vec<NodeInfo>>();
            nodes_from_bucket.sort_by_key(|ref info| &info.key ^ key);
            let space_left = closest.capacity() - closest.len();
            nodes_from_bucket.truncate(space_left);
            closest.append(&mut nodes_from_bucket);
            if closest.capacity() == closest.len() {
               return closest;
            }
         }
         ceiling = floor;
         master_key.flip_bit(floor);
         floor = match master_key.height() {
            Some(height) => height,
            None => 1
         }
      }

      // If the master key algorithm wasn't enough, just pour from the higher buckets
      for bucket_index in (ideal_bucket+1)..KEY_SIZE {
         if closest.capacity() == closest.len() {
            break;
         }
         let mut nodes_from_bucket = self.buckets[bucket_index].clone().entries.into_iter().collect::<Vec<NodeInfo>>();
         nodes_from_bucket.sort_by_key(|ref info| &info.key ^ key);
         let space_left = closest.capacity() - closest.len();
         nodes_from_bucket.truncate(space_left);
         closest.append(&mut nodes_from_bucket);
      }
      closest
   }

   /// Returns the appropriate position for a node, by computing
   /// the last bit of their distance set to 1. None if we are
   /// attempting to add the parent key.
   fn bucket_for_node(&self, key : &Hash160) -> Option<usize> {
       (&self.parent_key ^ key).height()
   }

   fn revert_conflict(&mut self, conflict : EvictionConflict) {
      if let Some(index) = self.bucket_for_node(&conflict.inserted.key) {
         let bucket  = &mut self.buckets[index];
         let evictor = &mut bucket.entries.iter_mut().find(|ref info| conflict.inserted.key == info.key).unwrap();
         mem::replace::<NodeInfo>(evictor, conflict.evicted);
      }
   }
}

impl Bucket {
   pub fn new() -> Bucket {
      Bucket { entries : VecDeque::<NodeInfo>::with_capacity(BUCKET_DEPTH) }
   }
}

#[cfg(test)]
mod tests {
    use super::*;
    use hash::Hash160;
    use std::net;
    use std::str::FromStr;

    #[test]
    fn new_routing_table_is_empty() {
       let parent_key = Hash160::random();
       let table = RoutingTable::new(parent_key);
       let test_hash = Hash160::random();

       assert!(table.specific_node(&test_hash).is_none());
    }

    #[test]
    fn inserting_and_retrieving_specific_node() {
       let node_info = NodeInfo {
          key  : Hash160::random(),
          ip   : net::IpAddr::from_str("0.0.0.0").unwrap(),
          port : 50000
       };

       let mut table = RoutingTable::new(Hash160::random());
       table.insert_node(node_info.clone());
       assert_eq!(table.specific_node(&node_info.key), Some(node_info));
    }

    impl RoutingTable {
       pub fn fill_bucket(&mut self, bucket_index : usize, fill_quantity : u8) {
          // Otherwise this helper function becomes quite complex.
          assert!(bucket_index > 7);
          let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();
          for i in 0..fill_quantity {
             let mut key = self.parent_key.clone();
             key.flip_bit(bucket_index);

             key.raw[0] = i as u8;
             let info = NodeInfo {
                key  : key,
                ip   : any_ip.clone(),
                port : 0
             };
             self.insert_node(info);
          }
       }
    }

    #[test]
    fn inserting_in_a_full_bucket_causes_eviction_conflict() {
       let mut parent_key = Hash160::blank();
       parent_key.raw[1] = 1; // This will guarantee all nodes will fall on the same bucket.
       let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();

       let mut table = RoutingTable::new(parent_key);

       table.fill_bucket(8, super::BUCKET_DEPTH as u8);
       assert!(table.conflicts.is_empty());

       // When we add another node to the same bucket, we cause a conflict.
       let mut key = Hash160::blank();
       key.raw[0] = 0xFF;
       let info = NodeInfo {
          key  : key,
          ip   : any_ip.clone(),
          port : 0
       };
       table.insert_node(info);
       assert_eq!(table.conflicts.len(), 1);

       let conflict = table.conflicts.first().unwrap();
       // We evicted the oldest node, which has a blank key.
       assert!(table.specific_node(&conflict.inserted.key).is_some());
    }

    #[test]
    fn reverting_an_eviction_conflict_reinserts_the_evicted_node_in_place_of_evictor() {
       let mut parent_key = Hash160::blank();
       parent_key.raw[1] = 1; // This will guarantee all nodes will fall on the same bucket.
       let any_ip = net::IpAddr::from_str("0.0.0.0").unwrap();

       let mut table = RoutingTable::new(parent_key);

       table.fill_bucket(8, super::BUCKET_DEPTH as u8);
       assert!(table.conflicts.is_empty());

       // When we add another node to the same bucket, we cause a conflict.
       let mut key = Hash160::blank();
       key.raw[0] = 0xFF;
       let info = NodeInfo {
          key  : key,
          ip   : any_ip.clone(),
          port : 0
       };
       table.insert_node(info);
       assert_eq!(table.conflicts.len(), 1);
       let conflict = table.conflicts.pop().unwrap();

       table.revert_conflict(conflict.clone());
       // The evictor has been removed.
       assert!(table.specific_node(&conflict.inserted.key).is_none());
       // And the evicted has been reinserted.
       assert!(table.specific_node(&conflict.evicted.key).is_some());
    }

    #[test]
    fn lookup_for_a_stored_node() {
       let mut table = RoutingTable::new(Hash160::random());
       let node = NodeInfo {
          key  : Hash160::random(),
          ip   : net::IpAddr::from_str("0.0.0.0").unwrap(),
          port : 0,
       };
       table.insert_node(node.clone());

       assert_eq!(table.lookup(&node.key, 20), LookupResult::Found(node));
    }

    #[test]
    fn lookup_for_self() {
       let parent_key = Hash160::random();
       let table = RoutingTable::new(parent_key.clone());
       assert_eq!(table.lookup(&parent_key, 20), LookupResult::Myself);
    }

    #[test]
    fn ascending_lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(8); // Bucket 8
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }

    #[test]
    fn descending_lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(51); // Bucket 51
       node_key.raw[0] = 0xFF;
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }

    #[test]
    fn lookup_on_a_sparse_table() {
       let mut table = RoutingTable::new(Hash160::random());
       for i in (10..50).filter(|x| x%2 == 0) {
         table.fill_bucket(i, 2);
       }
       let mut node_key = table.parent_key.clone();
       node_key.flip_bit(25); // Bucket 25
       node_key.raw[0] = 0xFF;
       if let LookupResult::ClosestNodes(nodes) = table.lookup(&node_key,5) {
          assert_eq!(nodes.len(), 5);

          // Ensure they are ordered by ascending distance
          for (current_node, next_node) in nodes.iter().zip(nodes.iter().skip(1)) {
             assert!((&current_node.key ^ &node_key) <= (&next_node.key ^ &node_key));
          }
       }
       else {
          panic!("We shouldn't have found the node!");
       }
    }
}
<|endoftext|>


<commit_before>//! Types/fns concerning URLs (see RFC 3986)

import map;
import map::*;

export url, userinfo, query, from_str, to_str;

type url = {
    scheme: ~str,
    user: option<userinfo>,
    host: ~str,
    path: ~str,
    query: query,
    fragment: option<~str>
};

type userinfo = {
    user: ~str,
    pass: option<~str>
};

type query = map::hashmap<~str, ~str>;

fn url(-scheme: ~str, -user: option<userinfo>, -host: ~str,
       -path: ~str, -query: query, -fragment: option<~str>) -> url {
    { scheme: scheme, user: user, host: host,
     path: path, query: query, fragment: fragment }
}

fn userinfo(-user: ~str, -pass: option<~str>) -> userinfo {
    {user: user, pass: pass}
}

fn split_char_first(s: ~str, c: char) -> (~str, ~str) {
    let mut v = str::splitn_char(s, c, 1);
    if v.len() == 1 {
        ret (s, ~"");
    } else {
        ret (vec::shift(v), vec::pop(v));
    }
}

fn userinfo_from_str(uinfo: ~str) -> userinfo {
    let (user, p) = split_char_first(uinfo, ':');
    let pass = if str::len(p) == 0 {
        option::none
    } else {
        option::some(p)
    };
    ret userinfo(user, pass);
}

fn userinfo_to_str(-userinfo: userinfo) -> ~str {
    if option::is_some(userinfo.pass) {
        ret str::concat(~[copy userinfo.user, ~":",
                          option::unwrap(copy userinfo.pass),
                          ~"@"]);
    } else {
        ret str::concat(~[copy userinfo.user, ~"@"]);
    }
}

fn query_from_str(rawquery: ~str) -> query {
    let query: query = map::str_hash();
    if str::len(rawquery) != 0 {
        for str::split_char(rawquery, '&').each |p| {
            let (k, v) = split_char_first(p, '=');
            query.insert(k, v);
        };
    }
    ret query;
}

fn query_to_str(query: query) -> ~str {
    let mut strvec = ~[];
    for query.each |k, v| {
        strvec += ~[#fmt("%s=%s", k, v)];
    };
    ret str::connect(strvec, ~"&");
}

fn get_scheme(rawurl: ~str) -> option::option<(~str, ~str)> {
    for str::each_chari(rawurl) |i,c| {
        if char::is_alphabetic(c) {
            again;
        } else if c == ':' && i != 0 {
            ret option::some((rawurl.slice(0,i),
                              rawurl.slice(i+3,str::len(rawurl))));
        } else {
            ret option::none;
        }
    };
    ret option::none;
}

/**
 * Parse a `str` to a `url`
 *
 * # Arguments
 *
 * `rawurl` - a string representing a full url, including scheme.
 *
 * # Returns
 *
 * a `url` that contains the parsed representation of the url.
 *
 */

fn from_str(rawurl: ~str) -> result::result<url, ~str> {
    let mut schm = get_scheme(rawurl);
    if option::is_none(schm) {
        ret result::err(~"invalid scheme");
    }
    let (scheme, rest) = option::unwrap(schm);
    let (u, rest) = split_char_first(rest, '@');
    let user = if str::len(rest) == 0 {
        option::none
    } else {
        option::some(userinfo_from_str(u))
    };
    let rest = if str::len(rest) == 0 {
         u
    } else {
        rest
    };
    let (rest, frag) = split_char_first(rest, '#');
    let fragment = if str::len(frag) == 0 {
        option::none
    } else {
        option::some(frag)
    };
    let (rest, query) = split_char_first(rest, '?');
    let query = query_from_str(query);
    let (host, pth) = split_char_first(rest, '/');
    let mut path = pth;
    if str::len(path) != 0 {
        str::unshift_char(path, '/');
    }

    ret result::ok(url(scheme, user, host, path, query, fragment));
}

/**
 * Format a `url` as a string
 *
 * # Arguments
 *
 * `url` - a url.
 *
 * # Returns
 *
 * a `str` that contains the formatted url. Note that this will usually
 * be an inverse of `from_str` but might strip out unneeded separators.
 * for example, "http://somehost.com?", when parsed and formatted, will
 * result in just "http://somehost.com".
 *
 */
fn to_str(url: url) -> ~str {
    let user = if option::is_some(url.user) {
      userinfo_to_str(option::unwrap(copy url.user))
    } else {
       ~""
    };
    let query = if url.query.size() == 0 {
        ~""
    } else {
        str::concat(~[~"?", query_to_str(url.query)])
    };
    let fragment = if option::is_some(url.fragment) {
        str::concat(~[~"#", option::unwrap(copy url.fragment)])
    } else {
        ~""
    };

    ret str::concat(~[copy url.scheme,
                      ~"://",
                      user,
                      copy url.host,
                      copy url.path,
                      query,
                      fragment]);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_full_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_userless_url_parse_and_format() {
        let url = ~"http://rust-lang.org/doc?s=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_queryless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_empty_query_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?#something";
        let should_be = ~"http://user:pass@rust-lang.org/doc#something";
        assert to_str(result::unwrap(from_str(url))) == should_be;
    }

    #[test]
    fn test_fragmentless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?q=v";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_minimal_url_parse_and_format() {
        let url = ~"http://rust-lang.org/doc";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_scheme_host_only_url_parse_and_format() {
        let url = ~"http://rust-lang.org";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_pathless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org?q=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_scheme_host_fragment_only_url_parse_and_format() {
        let url = ~"http://rust-lang.org#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

}<commit_msg>std: Make url a sendable type<commit_after>//! Types/fns concerning URLs (see RFC 3986)

export url, userinfo, query, from_str, to_str;

type url = {
    scheme: ~str,
    user: option<userinfo>,
    host: ~str,
    path: ~str,
    query: query,
    fragment: option<~str>
};

type userinfo = {
    user: ~str,
    pass: option<~str>
};

type query = ~[(~str, ~str)];

fn url(-scheme: ~str, -user: option<userinfo>, -host: ~str,
       -path: ~str, -query: query, -fragment: option<~str>) -> url {
    { scheme: scheme, user: user, host: host,
     path: path, query: query, fragment: fragment }
}

fn userinfo(-user: ~str, -pass: option<~str>) -> userinfo {
    {user: user, pass: pass}
}

fn split_char_first(s: ~str, c: char) -> (~str, ~str) {
    let mut v = str::splitn_char(s, c, 1);
    if v.len() == 1 {
        ret (s, ~"");
    } else {
        ret (vec::shift(v), vec::pop(v));
    }
}

fn userinfo_from_str(uinfo: ~str) -> userinfo {
    let (user, p) = split_char_first(uinfo, ':');
    let pass = if str::len(p) == 0 {
        option::none
    } else {
        option::some(p)
    };
    ret userinfo(user, pass);
}

fn userinfo_to_str(-userinfo: userinfo) -> ~str {
    if option::is_some(userinfo.pass) {
        ret str::concat(~[copy userinfo.user, ~":",
                          option::unwrap(copy userinfo.pass),
                          ~"@"]);
    } else {
        ret str::concat(~[copy userinfo.user, ~"@"]);
    }
}

fn query_from_str(rawquery: ~str) -> query {
    let mut query: query = ~[];
    if str::len(rawquery) != 0 {
        for str::split_char(rawquery, '&').each |p| {
            let (k, v) = split_char_first(p, '=');
            vec::push(query, (k, v));
        };
    }
    ret query;
}

fn query_to_str(query: query) -> ~str {
    let mut strvec = ~[];
    for query.each |kv| {
        let (k, v) = kv;
        strvec += ~[#fmt("%s=%s", k, v)];
    };
    ret str::connect(strvec, ~"&");
}

fn get_scheme(rawurl: ~str) -> option::option<(~str, ~str)> {
    for str::each_chari(rawurl) |i,c| {
        if char::is_alphabetic(c) {
            again;
        } else if c == ':' && i != 0 {
            ret option::some((rawurl.slice(0,i),
                              rawurl.slice(i+3,str::len(rawurl))));
        } else {
            ret option::none;
        }
    };
    ret option::none;
}

/**
 * Parse a `str` to a `url`
 *
 * # Arguments
 *
 * `rawurl` - a string representing a full url, including scheme.
 *
 * # Returns
 *
 * a `url` that contains the parsed representation of the url.
 *
 */

fn from_str(rawurl: ~str) -> result::result<url, ~str> {
    let mut schm = get_scheme(rawurl);
    if option::is_none(schm) {
        ret result::err(~"invalid scheme");
    }
    let (scheme, rest) = option::unwrap(schm);
    let (u, rest) = split_char_first(rest, '@');
    let user = if str::len(rest) == 0 {
        option::none
    } else {
        option::some(userinfo_from_str(u))
    };
    let rest = if str::len(rest) == 0 {
         u
    } else {
        rest
    };
    let (rest, frag) = split_char_first(rest, '#');
    let fragment = if str::len(frag) == 0 {
        option::none
    } else {
        option::some(frag)
    };
    let (rest, query) = split_char_first(rest, '?');
    let query = query_from_str(query);
    let (host, pth) = split_char_first(rest, '/');
    let mut path = pth;
    if str::len(path) != 0 {
        str::unshift_char(path, '/');
    }

    ret result::ok(url(scheme, user, host, path, query, fragment));
}

/**
 * Format a `url` as a string
 *
 * # Arguments
 *
 * `url` - a url.
 *
 * # Returns
 *
 * a `str` that contains the formatted url. Note that this will usually
 * be an inverse of `from_str` but might strip out unneeded separators.
 * for example, "http://somehost.com?", when parsed and formatted, will
 * result in just "http://somehost.com".
 *
 */
fn to_str(url: url) -> ~str {
    let user = if option::is_some(url.user) {
      userinfo_to_str(option::unwrap(copy url.user))
    } else {
       ~""
    };
    let query = if url.query.len() == 0 {
        ~""
    } else {
        str::concat(~[~"?", query_to_str(url.query)])
    };
    let fragment = if option::is_some(url.fragment) {
        str::concat(~[~"#", option::unwrap(copy url.fragment)])
    } else {
        ~""
    };

    ret str::concat(~[copy url.scheme,
                      ~"://",
                      user,
                      copy url.host,
                      copy url.path,
                      query,
                      fragment]);
}

#[cfg(test)]
mod tests {
    #[test]
    fn test_full_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?s=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_userless_url_parse_and_format() {
        let url = ~"http://rust-lang.org/doc?s=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_queryless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_empty_query_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?#something";
        let should_be = ~"http://user:pass@rust-lang.org/doc#something";
        assert to_str(result::unwrap(from_str(url))) == should_be;
    }

    #[test]
    fn test_fragmentless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org/doc?q=v";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_minimal_url_parse_and_format() {
        let url = ~"http://rust-lang.org/doc";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_scheme_host_only_url_parse_and_format() {
        let url = ~"http://rust-lang.org";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_pathless_url_parse_and_format() {
        let url = ~"http://user:pass@rust-lang.org?q=v#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

    #[test]
    fn test_scheme_host_fragment_only_url_parse_and_format() {
        let url = ~"http://rust-lang.org#something";
        assert to_str(result::unwrap(from_str(url))) == url;
    }

}<|endoftext|>


<commit_before>
use super::ast::BinOpKind;
use super::ast::BinOpKind::*;
use super::ast::BuilderKind::*;
use super::ast::ScalarKind::*;
use super::ast::Expr;
use super::ast::Type;
use super::ast::Type::*;
use super::ast::Parameter;
use super::ast::ExprKind::*;
use super::partial_types::*;

// TODO: These methods could take a mutable string as an argument, or even a fmt::Format.

/// A trait for printing types.
pub trait PrintableType: Clone {
    fn print(&self) -> String;
}

/// Print implementation for full Types
impl PrintableType for Type {
    fn print(&self) -> String {
        match *self {
            Scalar(Bool) => "bool".to_string(),
            Scalar(I32) => "i32".to_string(),
            Vector(ref elem) => format!("vec[{}]", elem.print()),

            Struct(ref elems) => {
                let mut res = String::new();
                res.push_str("{");
                for (i, t) in elems.iter().enumerate() {
                    if i > 0 { res.push_str(","); }
                    res.push_str(&t.print());
                }
                res.push_str("}");
                res
            },

            Function(ref params, ref ret) => {
                let mut res = String::new();
                res.push_str("(");
                for (i, p) in params.iter().enumerate() {
                    if i > 0 { res.push_str(","); }
                    res.push_str(&p.print());
                }
                res.push_str(")=>");
                res.push_str(&ret.print());
                res
            },

            Builder(Appender(ref t)) => format!("appender[{}]", t.print()),
            Builder(Merger(ref t, op)) => format!("merger[{},{}]", t.print(), print_binop(op)),
        }
    }
}

/// Print implementation for PartialTypes
impl PrintableType for PartialType {
    fn print(&self) -> String {
        use partial_types::PartialType::*;
        use partial_types::PartialBuilderKind::*;
        match *self {
            Unknown => "?".to_string(),
            Scalar(Bool) => "bool".to_string(),
            Scalar(I32) => "i32".to_string(),
            Vector(ref elem) => format!("vec[{}]", elem.print()),

            Struct(ref elems) => {
                let mut res = String::new();
                res.push_str("{");
                for (i, t) in elems.iter().enumerate() {
                    if i > 0 { res.push_str(","); }
                    res.push_str(&t.print());
                }
                res.push_str("}");
                res
            },

            Function(ref params, ref ret) => {
                let mut res = String::new();
                res.push_str("(");
                for (i, p) in params.iter().enumerate() {
                    if i > 0 { res.push_str(","); }
                    res.push_str(&p.print());
                }
                res.push_str(")=>");
                res.push_str(&ret.print());
                res
            },

            Builder(Appender(ref elem)) => format!("appender[{}]", elem.print()),
            Builder(Merger(ref t, op)) => format!("merger[{},{}]", t.print(), print_binop(op)),
        }
    }
}

/// Print a type.
pub fn print_type<T: PrintableType>(ty: &T) -> String {
    ty.print()
}

/// Print an expression concisely (without any type annotations).
pub fn print_expr<T: PrintableType>(expr: &Expr<T>) -> String {
    print_expr_impl(expr, false)
}

/// Print an expression with type annotations on all symbols.
pub fn print_typed_expr<T: PrintableType>(expr: &Expr<T>) -> String {
    print_expr_impl(expr, true)
}

/// Main work to print an expression.
fn print_expr_impl<T: PrintableType>(expr: &Expr<T>, typed: bool) -> String {
    match expr.kind {
        BoolLiteral(v) => format!("{}", v),
        I32Literal(v) => format!("{}", v),

        Ident(ref symbol) => {
            if typed {
                format!("{}:{}", symbol, expr.ty.print())
            } else {
                format!("{}", symbol)
            }
        }

        BinOp(kind, ref left, ref right) =>
            format!("({}{}{})",
                    print_expr_impl(left, typed),
                    print_binop(kind),
                    print_expr_impl(right, typed)),

        Let(ref symbol, ref value, ref body) => {
            if typed {
                format!("let {}:{}=({});{}",
                        symbol,
                        value.ty.print(),
                        print_expr_impl(value, typed),
                        print_expr_impl(body, typed))
            } else {
                format!("let {}=({});{}",
                        symbol,
                        print_expr_impl(value, typed),
                        print_expr_impl(body, typed))
            }
        }

        MakeStruct(ref exprs) => {
            let mut res = String::new();
            res.push_str("{");
            for (i, e) in exprs.iter().enumerate() {
                if i > 0 { res.push_str(","); }
                res.push_str(&print_expr_impl(e, typed));
            }
            res.push_str("}");
            res
        }

        MakeVector(ref exprs) => {
            let mut res = String::new();
            res.push_str("[");
            for (i, e) in exprs.iter().enumerate() {
                if i > 0 { res.push_str(","); }
                res.push_str(&print_expr_impl(e, typed));
            }
            res.push_str("]");
            res
        }

        Lambda(ref params, ref body) => {
            let mut res = String::new();
            res.push_str("|");
            for (i, p) in params.iter().enumerate() {
                if i > 0 { res.push_str(","); }
                res.push_str(&print_parameter(p, typed));
            }
            res.push_str("|");
            res.push_str(&print_expr_impl(body, typed));
            res
        }

        NewBuilder => expr.ty.print(),

        Res(ref builder) => format!("result({})", print_expr_impl(builder, typed)),

        Merge(ref builder, ref value) => {
            format!("merge({},{})", print_expr_impl(builder, typed), print_expr_impl(value, typed))
        }

        For(ref data, ref builder, ref func) => {
            format!("for({},{},{})",
                print_expr_impl(data, typed),
                print_expr_impl(builder, typed),
                print_expr_impl(func, typed))
        }

        If(ref cond, ref on_true, ref on_false) => {
            format!("if({},{},{})",
                print_expr_impl(cond, typed),
                print_expr_impl(on_true, typed),
                print_expr_impl(on_false, typed))
        }

        Apply(ref func, ref params) => {
            let mut res = String::new();
            res.push_str(&format!("({})", print_expr_impl(func, typed)));
            res.push_str("(");
            for (i, p) in params.iter().enumerate() {
                if i > 0 { res.push_str(","); }
                res.push_str(&print_expr_impl(p, typed));
            }
            res.push_str(")");
            res
        }
    }
}

fn print_binop(op: BinOpKind) -> String {
    match op {
        Add => "+",
        Subtract => "-",
        Multiply => "*",
        Divide => "/"
    }.to_string()
}

/// Print a parameter, optionally showing its type.
fn print_parameter<T: PrintableType>(param: &Parameter<T>, typed: bool) -> String {
    if typed {
        format!("{}:{}", param.name, param.ty.print())
    } else {
        format!("{}", param.name)
    }
}<commit_msg>Simpler printing<commit_after>use std::iter::Iterator;

use super::ast::BinOpKind;
use super::ast::BinOpKind::*;
use super::ast::BuilderKind::*;
use super::ast::ScalarKind::*;
use super::ast::Expr;
use super::ast::Type;
use super::ast::Type::*;
use super::ast::Parameter;
use super::ast::ExprKind::*;
use super::partial_types::*;

// TODO: These methods could take a mutable string as an argument, or even a fmt::Format.

/// A trait for printing types.
pub trait PrintableType: Clone {
    fn print(&self) -> String;
}

/// Print implementation for full Types
impl PrintableType for Type {
    fn print(&self) -> String {
        match *self {
            Scalar(Bool) => "bool".to_string(),
            Scalar(I32) => "i32".to_string(),
            Vector(ref elem) => format!("vec[{}]", elem.print()),
            Struct(ref elems) => join("{", ",", "}", elems.iter().map(|e| e.print())),
            Function(ref params, ref ret) => {
                let mut res = join("(", ",", ")=>", params.iter().map(|e| e.print()));
                res.push_str(&ret.print());
                res
            },
            Builder(Appender(ref t)) => format!("appender[{}]", t.print()),
            Builder(Merger(ref t, op)) => format!("merger[{},{}]", t.print(), print_binop(op)),
        }
    }
}

/// Print implementation for PartialTypes
impl PrintableType for PartialType {
    fn print(&self) -> String {
        use partial_types::PartialType::*;
        use partial_types::PartialBuilderKind::*;
        match *self {
            Unknown => "?".to_string(),
            Scalar(Bool) => "bool".to_string(),
            Scalar(I32) => "i32".to_string(),
            Vector(ref elem) => format!("vec[{}]", elem.print()),
            Struct(ref elems) => join("{", ",", "}", elems.iter().map(|e| e.print())),
            Function(ref params, ref ret) => {
                let mut res = join("(", ",", ")=>", params.iter().map(|e| e.print()));
                res.push_str(&ret.print());
                res
            },
            Builder(Appender(ref elem)) => format!("appender[{}]", elem.print()),
            Builder(Merger(ref t, op)) => format!("merger[{},{}]", t.print(), print_binop(op)),
        }
    }
}

/// Print a type.
pub fn print_type<T: PrintableType>(ty: &T) -> String {
    ty.print()
}

/// Print an expression concisely (without any type annotations).
pub fn print_expr<T: PrintableType>(expr: &Expr<T>) -> String {
    print_expr_impl(expr, false)
}

/// Print an expression with type annotations on all symbols.
pub fn print_typed_expr<T: PrintableType>(expr: &Expr<T>) -> String {
    print_expr_impl(expr, true)
}

/// Main work to print an expression.
fn print_expr_impl<T: PrintableType>(expr: &Expr<T>, typed: bool) -> String {
    match expr.kind {
        BoolLiteral(v) => format!("{}", v),
        I32Literal(v) => format!("{}", v),

        Ident(ref symbol) => {
            if typed {
                format!("{}:{}", symbol, expr.ty.print())
            } else {
                format!("{}", symbol)
            }
        }

        BinOp(kind, ref left, ref right) =>
            format!("({}{}{})",
                    print_expr_impl(left, typed),
                    print_binop(kind),
                    print_expr_impl(right, typed)),

        Let(ref symbol, ref value, ref body) => {
            if typed {
                format!("let {}:{}=({});{}",
                        symbol,
                        value.ty.print(),
                        print_expr_impl(value, typed),
                        print_expr_impl(body, typed))
            } else {
                format!("let {}=({});{}",
                        symbol,
                        print_expr_impl(value, typed),
                        print_expr_impl(body, typed))
            }
        }

        MakeStruct(ref exprs) =>
            join("{", ",", "}", exprs.iter().map(|e| print_expr_impl(e, typed))),

        MakeVector(ref exprs) =>
            join("[", ",", "]", exprs.iter().map(|e| print_expr_impl(e, typed))),

        Lambda(ref params, ref body) => {
            let mut res = join("|", ",", "|", params.iter().map(|e| print_parameter(e, typed)));
            res.push_str(&print_expr_impl(body, typed));
            res
        }

        NewBuilder => expr.ty.print(),

        Res(ref builder) => format!("result({})", print_expr_impl(builder, typed)),

        Merge(ref builder, ref value) => {
            format!("merge({},{})", print_expr_impl(builder, typed), print_expr_impl(value, typed))
        }

        For(ref data, ref builder, ref func) => {
            format!("for({},{},{})",
                print_expr_impl(data, typed),
                print_expr_impl(builder, typed),
                print_expr_impl(func, typed))
        }

        If(ref cond, ref on_true, ref on_false) => {
            format!("if({},{},{})",
                print_expr_impl(cond, typed),
                print_expr_impl(on_true, typed),
                print_expr_impl(on_false, typed))
        }

        Apply(ref func, ref params) => {
            let mut res = format!("({})", print_expr_impl(func, typed));
            res.push_str(&join("(", ",", ")", params.iter().map(|e| print_expr_impl(e, typed))));
            res
        }
    }
}

fn print_binop(op: BinOpKind) -> String {
    match op {
        Add => "+",
        Subtract => "-",
        Multiply => "*",
        Divide => "/"
    }.to_string()
}

/// Print a parameter, optionally showing its type.
fn print_parameter<T: PrintableType>(param: &Parameter<T>, typed: bool) -> String {
    if typed {
        format!("{}:{}", param.name, param.ty.print())
    } else {
        format!("{}", param.name)
    }
}

fn join<T:Iterator<Item=String>>(start: &str, sep: &str, end: &str, strings: T) -> String {
    let mut res = String::new();
    res.push_str(start);
    for (i, s) in strings.enumerate() {
        if i > 0 { res.push_str(sep); }
        res.push_str(&s);
    }
    res.push_str(end);
    res
}<|endoftext|>


<commit_before>use std::collections::VecDeque;
use std::marker::PhantomData;
use std::mem;

pub trait Primitive<T>: Sized {
    fn into_points<F>(self, f: F) where F: FnMut(T);
    fn into_lines<F>(self, f: F) where F: FnMut(Line<T>);
}

pub trait Polygonal<T>: Primitive<T> {
    fn into_triangles<F>(self, f: F) where F: FnMut(Triangle<T>);
}

pub trait MapPrimitiveInto<T, U> {
    type Output;

    fn map_points_into<F>(self, f: F) -> Self::Output where F: FnMut(T) -> U;
}

pub trait MapPrimitive<T, U>: Sized {
    type Output;

    fn map_points<F>(self, f: F) -> Map<Self, T, U, F> where F: FnMut(T) -> U;
}

pub trait RotatePrimitive {
    fn rotate(&mut self, n: isize);
}

pub trait DecomposePrimitive<T>: Sized {
    fn points(self) -> PointIter<Self, T>;
}

pub trait DecomposePolygon<T>: Sized {
    fn triangulate(self) -> TriangleIter<Self, T>;
}

impl<I, T, U, P, Q> MapPrimitive<T, U> for I
    where I: Iterator<Item = P>,
          P: MapPrimitiveInto<T, U, Output = Q>
{
    type Output = Q;

    fn map_points<F>(self, f: F) -> Map<Self, T, U, F>
        where F: FnMut(T) -> U
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    primitives: I,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(primitives: I, f: F) -> Self {
        Map {
            primitives: primitives,
            f: f,
            phantom_t: PhantomData,
            phantom_u: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
    where I: Iterator<Item = P>,
          F: FnMut(T) -> U,
          P: MapPrimitiveInto<T, U, Output = Q>
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.primitives.next().map(|primitive| primitive.map_points_into(|point| (self.f)(point)))
    }
}

impl<I, T, P> DecomposePrimitive<T> for I
    where I: Iterator<Item = P>,
          P: Primitive<T>
{
    fn points(self) -> PointIter<Self, T> {
        PointIter::new(self)
    }
}

pub struct PointIter<I, T> {
    primitives: I,
    points: VecDeque<T>,
}

impl<I, T> PointIter<I, T> {
    fn new(primitives: I) -> Self {
        PointIter {
            primitives: primitives,
            points: VecDeque::new(),
        }
    }
}

impl<I, T, P> Iterator for PointIter<I, T>
    where I: Iterator<Item = P>,
          P: Primitive<T>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(point) = self.points.pop_front() {
                return Some(point);
            }
            if let Some(primitive) = self.primitives.next() {
                primitive.into_points(|point| self.points.push_back(point))
            }
            else {
                return None;
            }
        }
    }
}

impl<I, T, P> DecomposePolygon<T> for I
    where I: Iterator<Item = P>,
          P: Polygonal<T>
{
    fn triangulate(self) -> TriangleIter<Self, T> {
        TriangleIter::new(self)
    }
}

pub struct TriangleIter<I, T> {
    polygons: I,
    triangles: VecDeque<Triangle<T>>,
}

impl<I, T> TriangleIter<I, T> {
    fn new(polygons: I) -> Self {
        TriangleIter {
            polygons: polygons,
            triangles: VecDeque::new(),
        }
    }
}

impl<I, T, P> Iterator for TriangleIter<I, T>
    where I: Iterator<Item = P>,
          P: Polygonal<T>
{
    type Item = Triangle<T>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(triangle) = self.triangles.pop_front() {
                return Some(triangle);
            }
            if let Some(polygon) = self.polygons.next() {
                polygon.into_triangles(|triangle| self.triangles.push_back(triangle))
            }
            else {
                return None;
            }
        }
    }
}

pub struct Line<T> {
    pub a: T,
    pub b: T,
}

impl<T> Line<T> {
    pub fn new(a: T, b: T) -> Self {
        Line { a: a, b: b }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Line { a, b } = self;
        Line::new(f(a), f(b))
    }
}

impl<T> Primitive<T> for Line<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Line { a, b } = self;
        f(a);
        f(b);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        f(self);
    }
}

impl<T> RotatePrimitive for Line<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a: a, b: b, c: c }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Primitive<T> for Triangle<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Triangle { a, b, c } = self;
        f(a);
        f(b);
        f(c);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        let Triangle { a, b, c } = self;
        f(Line::new(a.clone(), b.clone()));
        f(Line::new(b, c.clone()));
        f(Line::new(c, a));
    }
}

impl<T> Polygonal<T> for Triangle<T>
    where T: Clone
{
    fn into_triangles<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        f(self);
    }
}

impl<T> RotatePrimitive for Triangle<T>
    where T: Clone
{
    // TODO: This seems a bit odd. For `Triangle`, there are only two possible
    //       mutations, and the loops and additional swaps aren't necessary.
    fn rotate(&mut self, n: isize) {
        let n = (n % 3);
        if n >= 0 {
            for _ in 0..n {
                mem::swap(&mut self.a, &mut self.b);
                mem::swap(&mut self.b, &mut self.c);
            }
        }
        else {
            for _ in n..0 {
                mem::swap(&mut self.c, &mut self.b);
                mem::swap(&mut self.b, &mut self.a);
            }
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Primitive<T> for Quad<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Quad { a, b, c, d } = self;
        f(a);
        f(b);
        f(c);
        f(d);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        let Quad { a, b, c, d } = self;
        f(Line::new(a.clone(), b.clone()));
        f(Line::new(b, c.clone()));
        f(Line::new(c, d.clone()));
        f(Line::new(d, a));
    }
}

impl<T> Polygonal<T> for Quad<T>
    where T: Clone
{
    fn into_triangles<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        let Quad { a, b, c, d } = self;
        f(Triangle::new(a.clone(), b, c.clone()));
        f(Triangle::new(c, d, a));
    }
}

impl<T> RotatePrimitive for Quad<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        let n = (n % 4);
        if n >= 0 {
            for _ in 0..n {
                mem::swap(&mut self.a, &mut self.b);
                mem::swap(&mut self.b, &mut self.c);
                mem::swap(&mut self.c, &mut self.d);
            }
        }
        else {
            for _ in n..0 {
                mem::swap(&mut self.d, &mut self.c);
                mem::swap(&mut self.c, &mut self.b);
                mem::swap(&mut self.b, &mut self.a);
            }
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T, U> MapPrimitiveInto<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_points_into<F>(self, f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_points_into(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_points_into(f)),
        }
    }
}

impl<T> Primitive<T> for Polygon<T>
    where T: Clone
{
    fn into_points<F>(self, f: F)
        where F: FnMut(T)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_points(f),
            Polygon::Quad(quad) => quad.into_points(f),
        }
    }

    fn into_lines<F>(self, f: F)
        where F: FnMut(Line<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_lines(f),
            Polygon::Quad(quad) => quad.into_lines(f),
        }
    }
}

impl<T> Polygonal<T> for Polygon<T>
    where T: Clone
{
    fn into_triangles<F>(self, f: F)
        where F: FnMut(Triangle<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_triangles(f),
            Polygon::Quad(quad) => quad.into_triangles(f),
        }
    }
}

impl<T> RotatePrimitive for Polygon<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}
<commit_msg>Remove loops and unnecessary swaps from `rotate`.<commit_after>use std::collections::VecDeque;
use std::marker::PhantomData;
use std::mem;

pub trait Primitive<T>: Sized {
    fn into_points<F>(self, f: F) where F: FnMut(T);
    fn into_lines<F>(self, f: F) where F: FnMut(Line<T>);
}

pub trait Polygonal<T>: Primitive<T> {
    fn into_triangles<F>(self, f: F) where F: FnMut(Triangle<T>);
}

pub trait MapPrimitiveInto<T, U> {
    type Output;

    fn map_points_into<F>(self, f: F) -> Self::Output where F: FnMut(T) -> U;
}

pub trait MapPrimitive<T, U>: Sized {
    type Output;

    fn map_points<F>(self, f: F) -> Map<Self, T, U, F> where F: FnMut(T) -> U;
}

pub trait RotatePrimitive {
    fn rotate(&mut self, n: isize);
}

pub trait DecomposePrimitive<T>: Sized {
    fn points(self) -> PointIter<Self, T>;
}

pub trait DecomposePolygon<T>: Sized {
    fn triangulate(self) -> TriangleIter<Self, T>;
}

impl<I, T, U, P, Q> MapPrimitive<T, U> for I
    where I: Iterator<Item = P>,
          P: MapPrimitiveInto<T, U, Output = Q>
{
    type Output = Q;

    fn map_points<F>(self, f: F) -> Map<Self, T, U, F>
        where F: FnMut(T) -> U
    {
        Map::new(self, f)
    }
}

pub struct Map<I, T, U, F> {
    primitives: I,
    f: F,
    phantom_t: PhantomData<T>,
    phantom_u: PhantomData<U>,
}

impl<I, T, U, F> Map<I, T, U, F> {
    fn new(primitives: I, f: F) -> Self {
        Map {
            primitives: primitives,
            f: f,
            phantom_t: PhantomData,
            phantom_u: PhantomData,
        }
    }
}

impl<I, T, U, F, P, Q> Iterator for Map<I, T, U, F>
    where I: Iterator<Item = P>,
          F: FnMut(T) -> U,
          P: MapPrimitiveInto<T, U, Output = Q>
{
    type Item = Q;

    fn next(&mut self) -> Option<Self::Item> {
        self.primitives.next().map(|primitive| primitive.map_points_into(|point| (self.f)(point)))
    }
}

impl<I, T, P> DecomposePrimitive<T> for I
    where I: Iterator<Item = P>,
          P: Primitive<T>
{
    fn points(self) -> PointIter<Self, T> {
        PointIter::new(self)
    }
}

pub struct PointIter<I, T> {
    primitives: I,
    points: VecDeque<T>,
}

impl<I, T> PointIter<I, T> {
    fn new(primitives: I) -> Self {
        PointIter {
            primitives: primitives,
            points: VecDeque::new(),
        }
    }
}

impl<I, T, P> Iterator for PointIter<I, T>
    where I: Iterator<Item = P>,
          P: Primitive<T>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(point) = self.points.pop_front() {
                return Some(point);
            }
            if let Some(primitive) = self.primitives.next() {
                primitive.into_points(|point| self.points.push_back(point))
            }
            else {
                return None;
            }
        }
    }
}

impl<I, T, P> DecomposePolygon<T> for I
    where I: Iterator<Item = P>,
          P: Polygonal<T>
{
    fn triangulate(self) -> TriangleIter<Self, T> {
        TriangleIter::new(self)
    }
}

pub struct TriangleIter<I, T> {
    polygons: I,
    triangles: VecDeque<Triangle<T>>,
}

impl<I, T> TriangleIter<I, T> {
    fn new(polygons: I) -> Self {
        TriangleIter {
            polygons: polygons,
            triangles: VecDeque::new(),
        }
    }
}

impl<I, T, P> Iterator for TriangleIter<I, T>
    where I: Iterator<Item = P>,
          P: Polygonal<T>
{
    type Item = Triangle<T>;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            if let Some(triangle) = self.triangles.pop_front() {
                return Some(triangle);
            }
            if let Some(polygon) = self.polygons.next() {
                polygon.into_triangles(|triangle| self.triangles.push_back(triangle))
            }
            else {
                return None;
            }
        }
    }
}

pub struct Line<T> {
    pub a: T,
    pub b: T,
}

impl<T> Line<T> {
    pub fn new(a: T, b: T) -> Self {
        Line { a: a, b: b }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Line<T> {
    type Output = Line<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Line { a, b } = self;
        Line::new(f(a), f(b))
    }
}

impl<T> Primitive<T> for Line<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Line { a, b } = self;
        f(a);
        f(b);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        f(self);
    }
}

impl<T> RotatePrimitive for Line<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        if n % 2 != 0 {
            mem::swap(&mut self.a, &mut self.b);
        }
    }
}

pub struct Triangle<T> {
    pub a: T,
    pub b: T,
    pub c: T,
}

impl<T> Triangle<T> {
    pub fn new(a: T, b: T, c: T) -> Self {
        Triangle { a: a, b: b, c: c }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Triangle<T> {
    type Output = Triangle<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Triangle { a, b, c } = self;
        Triangle::new(f(a), f(b), f(c))
    }
}

impl<T> Primitive<T> for Triangle<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Triangle { a, b, c } = self;
        f(a);
        f(b);
        f(c);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        let Triangle { a, b, c } = self;
        f(Line::new(a.clone(), b.clone()));
        f(Line::new(b, c.clone()));
        f(Line::new(c, a));
    }
}

impl<T> Polygonal<T> for Triangle<T>
    where T: Clone
{
    fn into_triangles<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        f(self);
    }
}

impl<T> RotatePrimitive for Triangle<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        let n = ((n % 3) + 3) % 3;
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
        }
        else if n == 2 {
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub struct Quad<T> {
    pub a: T,
    pub b: T,
    pub c: T,
    pub d: T,
}

impl<T> Quad<T> {
    pub fn new(a: T, b: T, c: T, d: T) -> Self {
        Quad {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl<T, U> MapPrimitiveInto<T, U> for Quad<T> {
    type Output = Quad<U>;

    fn map_points_into<F>(self, mut f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        let Quad { a, b, c, d } = self;
        Quad::new(f(a), f(b), f(c), f(d))
    }
}

impl<T> Primitive<T> for Quad<T>
    where T: Clone
{
    fn into_points<F>(self, mut f: F)
        where F: FnMut(T)
    {
        let Quad { a, b, c, d } = self;
        f(a);
        f(b);
        f(c);
        f(d);
    }

    fn into_lines<F>(self, mut f: F)
        where F: FnMut(Line<T>)
    {
        let Quad { a, b, c, d } = self;
        f(Line::new(a.clone(), b.clone()));
        f(Line::new(b, c.clone()));
        f(Line::new(c, d.clone()));
        f(Line::new(d, a));
    }
}

impl<T> Polygonal<T> for Quad<T>
    where T: Clone
{
    fn into_triangles<F>(self, mut f: F)
        where F: FnMut(Triangle<T>)
    {
        let Quad { a, b, c, d } = self;
        f(Triangle::new(a.clone(), b, c.clone()));
        f(Triangle::new(c, d, a));
    }
}

impl<T> RotatePrimitive for Quad<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        let n = ((n % 4) + 4) % 4;
        if n == 1 {
            mem::swap(&mut self.a, &mut self.b);
            mem::swap(&mut self.b, &mut self.c);
            mem::swap(&mut self.c, &mut self.d);
        }
        else if n == 2 {
            mem::swap(&mut self.a, &mut self.c);
            mem::swap(&mut self.b, &mut self.d);
        }
        else if n == 3 {
            mem::swap(&mut self.d, &mut self.c);
            mem::swap(&mut self.c, &mut self.b);
            mem::swap(&mut self.b, &mut self.a);
        }
    }
}

pub enum Polygon<T> {
    Triangle(Triangle<T>),
    Quad(Quad<T>),
}

impl<T, U> MapPrimitiveInto<T, U> for Polygon<T> {
    type Output = Polygon<U>;

    fn map_points_into<F>(self, f: F) -> Self::Output
        where F: FnMut(T) -> U
    {
        match self {
            Polygon::Triangle(triangle) => Polygon::Triangle(triangle.map_points_into(f)),
            Polygon::Quad(quad) => Polygon::Quad(quad.map_points_into(f)),
        }
    }
}

impl<T> Primitive<T> for Polygon<T>
    where T: Clone
{
    fn into_points<F>(self, f: F)
        where F: FnMut(T)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_points(f),
            Polygon::Quad(quad) => quad.into_points(f),
        }
    }

    fn into_lines<F>(self, f: F)
        where F: FnMut(Line<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_lines(f),
            Polygon::Quad(quad) => quad.into_lines(f),
        }
    }
}

impl<T> Polygonal<T> for Polygon<T>
    where T: Clone
{
    fn into_triangles<F>(self, f: F)
        where F: FnMut(Triangle<T>)
    {
        match self {
            Polygon::Triangle(triangle) => triangle.into_triangles(f),
            Polygon::Quad(quad) => quad.into_triangles(f),
        }
    }
}

impl<T> RotatePrimitive for Polygon<T>
    where T: Clone
{
    fn rotate(&mut self, n: isize) {
        match *self {
            Polygon::Triangle(ref mut triangle) => triangle.rotate(n),
            Polygon::Quad(ref mut quad) => quad.rotate(n),
        }
    }
}
<|endoftext|>


<commit_before>use std::string;
use std::{char, f64, fmt, io, num, str, mem};
use std::ffi::CString;
use rustc_serialize as serialize;
use std::marker::PhantomData;
use proton_sys;

/*
Marshal encodes a Rust value as AMQP data in buffer based on its type.
If buffer is nil, or is not large enough, a new buffer  is created.

Returns the buffer used for encoding with len() adjusted to the actual size of data.

Rust types are encoded as follows

 +-------------------------------------+--------------------------------------------+
 |Rust type                            |AMQP type                                   |
 +-------------------------------------+--------------------------------------------+
 |bool                                 |bool                                        |
 +-------------------------------------+--------------------------------------------+
 |int8, int16, int32, int64 (int)      |byte, short, int, long (int or long)        |
 +-------------------------------------+--------------------------------------------+
 |uint8, uint16, uint32, uint64 (uint) |ubyte, ushort, uint, ulong (uint or ulong)  |
 +-------------------------------------+--------------------------------------------+
 |float32, float64                     |float, double.                              |
 +-------------------------------------+--------------------------------------------+
 |string                               |string                                      |
 +-------------------------------------+--------------------------------------------+
 |[]byte, Binary                       |binary                                      |
 +-------------------------------------+--------------------------------------------+
 |Symbol                               |symbol                                      |
 +-------------------------------------+--------------------------------------------+
 |interface{}                          |the contained type                          |
 +-------------------------------------+--------------------------------------------+
 |nil                                  |null                                        |
 +-------------------------------------+--------------------------------------------+
 |map[K]T                              |map with K and T converted as above         |
 +-------------------------------------+--------------------------------------------+
 |Map                                  |map, may have mixed types for keys, values  |
 +-------------------------------------+--------------------------------------------+
 |[]T                                  |list with T converted as above              |
 +-------------------------------------+--------------------------------------------+
 |List                                 |list, may have mixed types  values          |
 +-------------------------------------+--------------------------------------------+

TODO: Update the table to match rust types
TODO Rust types: array, slice, struct

Rust types that cannot be marshaled: complex64/128, uintptr, function, interface, channel
*/

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ErrorCode {
// ADD SOMETHING HERE
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ParserError {
    /// msg, line, col
    SyntaxError(ErrorCode, usize, usize),
    IoError(io::ErrorKind, &'static str),
}

// Builder and Parser have the same errors.
pub type BuilderError = ParserError;

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParseError(ParserError),
    ExpectedError(string::String, string::String),
    MissingFieldError(string::String),
    UnknownVariantError(string::String),
    ApplicationError(string::String)
}

#[derive(Clone, Copy, Debug)]
pub enum EncoderError {
    FmtError(fmt::Error),
    BadHashmapKey,
}

pub type EncodeResult = Result<(), EncoderError>;
pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Encoder<'e> {
    data: *mut proton_sys::pn_data_t,
    __phantom: PhantomData<&'e ()>
}

impl<'e> Encoder<'e> {
    fn new() -> Encoder<'e> {
        Encoder::with_capacity(16)
    }

    fn with_capacity(capacity: ::libc::size_t) -> Encoder<'e> {
        let data = unsafe{proton_sys::pn_data(capacity)};
        Encoder {data: data, __phantom: PhantomData}
    }
}

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_null(&mut *self.data);})
    }

    fn emit_usize(&mut self, v: usize) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v as u32);})
    }
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_ulong(&mut *self.data, v);})
    }
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v);})
    }
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ushort(&mut *self.data, v);})
    }
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ubyte(&mut *self.data, v);})
    }

    fn emit_isize(&mut self, v: isize) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v as i32);})
    }
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_long(&mut *self.data, v);})
    }
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v);})
    }
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_short(&mut *self.data, v);})
    }
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_byte(&mut *self.data, v);})
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_bool(&mut *self.data, v as u8);})
    }

    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v as f32);})
    }
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v);})
    }

    fn emit_char(&mut self, v: char) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_char(&mut *self.data, v as u32);})
    }

    fn emit_str(&mut self, slice: &str) -> EncodeResult {
        Ok(unsafe{
            let s = CString::new(slice).unwrap();
            let bytes = proton_sys::pn_bytes(slice.len() as proton_sys::size_t, s.as_ptr());
            proton_sys::pn_data_put_string(&mut *self.data, bytes);})
    }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_variant<F>(&mut self,
                            name: &str,
                            _id: usize,
                            cnt: usize,
                            f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_struct_variant<F>(&mut self,
                                   name: &str,
                                   id: usize,
                                   cnt: usize,
                                   f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant(name, id, cnt, f)
    }

    fn emit_enum_struct_variant_field<F>(&mut self,
                                         _: &str,
                                         idx: usize,
                                         f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant_arg(idx, f)
    }

    fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }
    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
}

/// Shortcut function to encode a `T` into a JSON `String`
pub fn encode<T: serialize::Encodable>(object: &T) -> Result<Vec<i8>, EncoderError> {
    let mut encoder = Encoder::new();
    try!(object.encode(&mut encoder));
    let mut size = 1024;
    let mut bytes = Vec::with_capacity(size);
    let mut result = proton_sys::PN_OVERFLOW;

    while result == proton_sys::PN_OVERFLOW {
        result = unsafe{proton_sys::pn_data_encode(encoder.data,
                                                   bytes.as_mut_ptr(),
                                                   size as u64) as i8};

        if result > 0 {
            unsafe {bytes.set_len(result as usize);}
            break;
        } else if result <= 0 {
            // not ok
            println!("ERROR");
            break;
        }

        size *= 2;
        bytes = Vec::with_capacity(size);
    }

    bytes.shrink_to_fit();
    Ok(bytes)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CStr;
    use std::slice;
    use std::str;
    use proton_sys;

    #[test]
    fn test_string_encoding() {
        let value = "testing";
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
            println!("{}", err);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});

        let type_name = unsafe{
            let t = proton_sys::pn_data_type(data);
            let name = proton_sys::pn_type_name(t);
            CStr::from_ptr(name).to_str().unwrap()
        };
        assert_eq!("PN_STRING", type_name);

        let data_content = unsafe {
            let pn_bytes = proton_sys::pn_data_get_string(data);
            let data: &[u8] = slice::from_raw_parts(pn_bytes.start as *const u8,
                                                    pn_bytes.size as usize);
            str::from_utf8(data).unwrap()
        };
        assert_eq!("testing", data_content);

    }
}
<commit_msg>more tests<commit_after>use std::string;
use std::{char, f64, fmt, io, num, str, mem};
use std::ffi::CString;
use rustc_serialize as serialize;
use std::marker::PhantomData;
use proton_sys;

/*
Marshal encodes a Rust value as AMQP data in buffer based on its type.
If buffer is nil, or is not large enough, a new buffer  is created.

Returns the buffer used for encoding with len() adjusted to the actual size of data.

Rust types are encoded as follows

 +-------------------------------------+--------------------------------------------+
 |Rust type                            |AMQP type                                   |
 +-------------------------------------+--------------------------------------------+
 |bool                                 |bool                                        |
 +-------------------------------------+--------------------------------------------+
 |int8, int16, int32, int64 (int)      |byte, short, int, long (int or long)        |
 +-------------------------------------+--------------------------------------------+
 |uint8, uint16, uint32, uint64 (uint) |ubyte, ushort, uint, ulong (uint or ulong)  |
 +-------------------------------------+--------------------------------------------+
 |float32, float64                     |float, double.                              |
 +-------------------------------------+--------------------------------------------+
 |string                               |string                                      |
 +-------------------------------------+--------------------------------------------+
 |[]byte, Binary                       |binary                                      |
 +-------------------------------------+--------------------------------------------+
 |Symbol                               |symbol                                      |
 +-------------------------------------+--------------------------------------------+
 |interface{}                          |the contained type                          |
 +-------------------------------------+--------------------------------------------+
 |nil                                  |null                                        |
 +-------------------------------------+--------------------------------------------+
 |map[K]T                              |map with K and T converted as above         |
 +-------------------------------------+--------------------------------------------+
 |Map                                  |map, may have mixed types for keys, values  |
 +-------------------------------------+--------------------------------------------+
 |[]T                                  |list with T converted as above              |
 +-------------------------------------+--------------------------------------------+
 |List                                 |list, may have mixed types  values          |
 +-------------------------------------+--------------------------------------------+

TODO: Update the table to match rust types
TODO Rust types: array, slice, struct

Rust types that cannot be marshaled: complex64/128, uintptr, function, interface, channel
*/

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ErrorCode {
// ADD SOMETHING HERE
}

#[derive(Clone, Copy, PartialEq, Debug)]
pub enum ParserError {
    /// msg, line, col
    SyntaxError(ErrorCode, usize, usize),
    IoError(io::ErrorKind, &'static str),
}

// Builder and Parser have the same errors.
pub type BuilderError = ParserError;

#[derive(Clone, PartialEq, Debug)]
pub enum DecoderError {
    ParseError(ParserError),
    ExpectedError(string::String, string::String),
    MissingFieldError(string::String),
    UnknownVariantError(string::String),
    ApplicationError(string::String)
}

#[derive(Clone, Copy, Debug)]
pub enum EncoderError {
    FmtError(fmt::Error),
    BadHashmapKey,
}

pub type EncodeResult = Result<(), EncoderError>;
pub type DecodeResult<T> = Result<T, DecoderError>;

pub struct Encoder<'e> {
    data: *mut proton_sys::pn_data_t,
    __phantom: PhantomData<&'e ()>
}

impl<'e> Encoder<'e> {
    fn new() -> Encoder<'e> {
        Encoder::with_capacity(16)
    }

    fn with_capacity(capacity: ::libc::size_t) -> Encoder<'e> {
        let data = unsafe{proton_sys::pn_data(capacity)};
        Encoder {data: data, __phantom: PhantomData}
    }
}

impl<'a> serialize::Encoder for Encoder<'a> {
    type Error = EncoderError;

    fn emit_nil(&mut self) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_null(&mut *self.data);})
    }

    fn emit_usize(&mut self, v: usize) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v as u32);})
    }
    fn emit_u64(&mut self, v: u64) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_ulong(&mut *self.data, v);})
    }
    fn emit_u32(&mut self, v: u32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_uint(&mut *self.data, v);})
    }
    fn emit_u16(&mut self, v: u16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ushort(&mut *self.data, v);})
    }
    fn emit_u8(&mut self, v: u8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_ubyte(&mut *self.data, v);})
    }

    fn emit_isize(&mut self, v: isize) -> EncodeResult {
        // NOTE(flaper87): check word size
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v as i32);})
    }
    fn emit_i64(&mut self, v: i64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_long(&mut *self.data, v);})
    }
    fn emit_i32(&mut self, v: i32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_int(&mut *self.data, v);})
    }
    fn emit_i16(&mut self, v: i16) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_short(&mut *self.data, v);})
    }
    fn emit_i8(&mut self, v: i8) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_byte(&mut *self.data, v);})
    }

    fn emit_bool(&mut self, v: bool) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_bool(&mut *self.data, v as u8);})
    }

    fn emit_f64(&mut self, v: f64) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v as f32);})
    }
    fn emit_f32(&mut self, v: f32) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_float(&mut *self.data, v);})
    }

    fn emit_char(&mut self, v: char) -> EncodeResult {
        Ok(unsafe{proton_sys::pn_data_put_char(&mut *self.data, v as u32);})
    }

    fn emit_str(&mut self, slice: &str) -> EncodeResult {
        Ok(unsafe{
            let s = CString::new(slice).unwrap();
            let bytes = proton_sys::pn_bytes(slice.len() as proton_sys::size_t, s.as_ptr());
            proton_sys::pn_data_put_string(&mut *self.data, bytes);})
    }

    fn emit_enum<F>(&mut self, _name: &str, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_variant<F>(&mut self,
                            name: &str,
                            _id: usize,
                            cnt: usize,
                            f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_enum_variant_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_enum_struct_variant<F>(&mut self,
                                   name: &str,
                                   id: usize,
                                   cnt: usize,
                                   f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant(name, id, cnt, f)
    }

    fn emit_enum_struct_variant_field<F>(&mut self,
                                         _: &str,
                                         idx: usize,
                                         f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_enum_variant_arg(idx, f)
    }

    fn emit_struct<F>(&mut self, _: &str, _: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_struct_field<F>(&mut self, name: &str, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_tuple_struct<F>(&mut self, _name: &str, len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq(len, f)
    }
    fn emit_tuple_struct_arg<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        self.emit_seq_elt(idx, f)
    }

    fn emit_option<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
    fn emit_option_none(&mut self) -> EncodeResult {
        self.emit_nil()
    }
    fn emit_option_some<F>(&mut self, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_seq<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }

    fn emit_map<F>(&mut self, _len: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        Ok(())
    }

    fn emit_map_elt_val<F>(&mut self, _idx: usize, f: F) -> EncodeResult where
        F: FnOnce(&mut Encoder<'a>) -> EncodeResult,
    {
        f(self)
    }
}

/// Shortcut function to encode a `T` into a JSON `String`
pub fn encode<T: serialize::Encodable>(object: &T) -> Result<Vec<i8>, EncoderError> {
    let mut encoder = Encoder::new();
    try!(object.encode(&mut encoder));
    let mut size = 1024;
    let mut bytes = Vec::with_capacity(size);
    let mut result = proton_sys::PN_OVERFLOW;

    while result == proton_sys::PN_OVERFLOW {
        result = unsafe{proton_sys::pn_data_encode(encoder.data,
                                                   bytes.as_mut_ptr(),
                                                   size as u64) as i8};

        if result > 0 {
            unsafe {bytes.set_len(result as usize);}
            break;
        } else if result <= 0 {
            // not ok
            println!("ERROR");
            break;
        }

        size *= 2;
        bytes = Vec::with_capacity(size);
    }

    bytes.shrink_to_fit();
    Ok(bytes)
}

#[cfg(test)]
mod tests {
    use super::*;
    use std::ffi::CStr;
    use std::slice;
    use std::str;
    use proton_sys;

    fn get_type_name<'a>(data: *mut proton_sys::pn_data_t) -> &'a str {
        unsafe{
            let t = proton_sys::pn_data_type(data);
            let name = proton_sys::pn_type_name(t);
            CStr::from_ptr(name).to_str().unwrap()
        }
    }

    #[test]
    fn test_string_encoding() {
        let value = "testing";
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
        assert_eq!("PN_STRING", get_type_name(data));

        let data_content = unsafe {
            let pn_bytes = proton_sys::pn_data_get_string(data);
            let data: &[u8] = slice::from_raw_parts(pn_bytes.start as *const u8,
                                                    pn_bytes.size as usize);
            str::from_utf8(data).unwrap()
        };
        assert_eq!(value, data_content);

    }

    #[test]
    fn test_u8_encoding() {
        let value = 1u8;
        let encoded = encode(&value).unwrap();
        let data;
        unsafe {
            data = proton_sys::pn_data(1024);
            let err = proton_sys::pn_data_decode(data,
                                                 encoded.as_ptr(),
                                                 encoded.len() as u64);
        }

        assert_eq!(1, unsafe{proton_sys::pn_data_size(data)});
        assert_eq!("PN_UBYTE", get_type_name(data));

        let data_content = unsafe {
            proton_sys::pn_data_get_ubyte(data)
        };
        assert_eq!(value, data_content);

    }
}
<|endoftext|>