<commit_before>use std::slice;
use binary::elf::strtab;
use binary::elf::sym;
use binary::elf::image::SharedObject;

static HASH_SEED: u32 = 5381;

/// Gnu hash function
pub fn hash (symbol: &str) -> u32 {
    let bytes = symbol.as_bytes();
    let mut hash = HASH_SEED;
    for b in bytes {
        hash = hash.wrapping_mul(32).wrapping_add(*b as u32).wrapping_add(hash);
    }
    hash
}

/// TODO add proper writeup for how this is constructed, how it resolves symbols, and how it works, see: https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
/// A Gnu Hash table as 4 sections:
/// 1. Header
/// 2. Bloom Filter
/// 3. Hash Buckets
/// 4. Hash Values
/// The header has is an array of four (4) u32s:
/// a. nbuckets
/// b. symndx
/// c. maskwords
/// d. shift2
pub struct GnuHash<'process> {
    nbuckets: u32,
    symindex: usize,
    maskwords: usize, // how many words our bloom filter mask has
    shift2: u32,
    maskbits: u32,
    bloomwords: &'process[usize], // either 32 or 64 bit masks, depending on platform
    maskwords_bitmask: u32,
    buckets: &'process[u32],
    hashvalues: &'process[u32],
}

impl<'process> GnuHash<'process> {
    pub fn new (hashtab: *const u32, total_dynsyms: usize) -> GnuHash<'process> {
        unsafe {
	    let nbuckets = *hashtab;
            let symindex = *hashtab.offset(1) as usize;
            let maskwords = *hashtab.offset(2) as usize;
            let shift2 = *hashtab.offset(3);
            let bloomwords_ptr = hashtab.offset(4) as *const usize;
            let buckets_ptr = bloomwords_ptr.offset(maskwords as isize) as *const u32;
            let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize);
            let hashvalues_ptr = buckets_ptr.offset(nbuckets as isize);
            let hashvalues = slice::from_raw_parts(hashvalues_ptr, total_dynsyms - symindex);
            let bloomwords = slice::from_raw_parts(bloomwords_ptr, maskwords);
            GnuHash {
                nbuckets: nbuckets,
                symindex: symindex,
                maskwords: maskwords,
                shift2: shift2,
                maskbits: 64, // because we don't have a compile time sizeof yet...
                bloomwords: bloomwords,
                hashvalues: hashvalues,
                buckets: buckets,
                maskwords_bitmask: ((maskwords as i32) - 1) as u32
            }
        }
    }

    #[inline(always)]
    fn lookup(&self, hash: u32, symbol: &str, bias: u64, strtab: &'process strtab::Strtab, symtab: &'process[sym::Sym]) -> Option<u64> {
        let mut idx = self.buckets[(hash % self.nbuckets) as usize] as usize;
        //println!("lookup idx = buckets[hash % nbuckets] = {}", idx);
        if idx == 0 { return None }
        let mut hash_idx = idx - self.symindex;
        let hash = hash & !1;
        // TODO: replace this with an iterator
        loop {
            let symbol_ = &symtab[idx];
            let h2 = self.hashvalues[hash_idx];
            idx += 1;
            hash_idx += 1;
            let name = &strtab[symbol_.st_name as usize];
            // println!("{}: h2 0x{:x} resolves to: {}", i, h2, name);
            if hash == (h2 & !1) && name == symbol {
                //println!("lookup match for {} at: 0x{:x}", symbol, symbol_.st_value);
                return Some(symbol_.st_value + bias)
            }
            if h2 & 1 == 1 { break } // end of chain
        }
        None
    }

    #[inline(always)]
    fn filter(&self, hash: u32, symbol: &str, bloom_idx: u32, bitmask: u32, h2: u32) -> bool {
        let filter = self.bloomwords[bloom_idx as usize];
        filter & (bitmask as usize) != (bitmask as usize) // if true, def _don't have_
    }

    /// Provide a name, a hash of that name, and the so to look in (which should have a reference to this self) -
    /// and we'll return an address option.
    pub fn find (&self, name: &str, hash: u32, so: &SharedObject) -> Option<u64> {

        let bloom_idx = (hash / self.maskbits) & self.maskwords_bitmask;
        let h2 = hash >> self.shift2;
        let bitmask = (1u64 << (hash % self.maskbits)) | (1u64 << (h2 % self.maskbits));
//        println!("lookup: maskwords: {} bloom_idx: {} bitmask: {} shift2: {}", self.maskwords, bloom_idx, bitmask, self.shift2);
        let does_not_have = self.filter(hash, name, bloom_idx, bitmask as u32, h2);
        if does_not_have {
            None
        } else {
            self.lookup(hash, name, so.load_bias, &so.strtab, &so.symtab)
        }
    }
}
<commit_msg>elf: refactor gnu_hash's filter to look prettier<commit_after>use std::slice;
use binary::elf::strtab;
use binary::elf::sym;
use binary::elf::image::SharedObject;

static HASH_SEED: u32 = 5381;

/// Gnu hash function
pub fn hash (symbol: &str) -> u32 {
    let bytes = symbol.as_bytes();
    let mut hash = HASH_SEED;
    for b in bytes {
        hash = hash.wrapping_mul(32).wrapping_add(*b as u32).wrapping_add(hash);
    }
    hash
}

/// TODO add proper writeup for how this is constructed, how it resolves symbols, and how it works, see: https://blogs.oracle.com/ali/entry/gnu_hash_elf_sections
/// A Gnu Hash table as 4 sections:
/// 1. Header
/// 2. Bloom Filter
/// 3. Hash Buckets
/// 4. Hash Values
/// The header has is an array of four (4) u32s:
/// a. nbuckets
/// b. symndx
/// c. maskwords
/// d. shift2
pub struct GnuHash<'process> {
    nbuckets: u32,
    symindex: usize,
    maskwords: usize, // how many words our bloom filter mask has
    shift2: u32,
    maskbits: u32,
    bloomwords: &'process[usize], // either 32 or 64 bit masks, depending on platform
    maskwords_bitmask: u32,
    buckets: &'process[u32],
    hashvalues: &'process[u32],
}

impl<'process> GnuHash<'process> {
    pub fn new (hashtab: *const u32, total_dynsyms: usize) -> GnuHash<'process> {
        unsafe {
	    let nbuckets = *hashtab;
            let symindex = *hashtab.offset(1) as usize;
            let maskwords = *hashtab.offset(2) as usize;
            let shift2 = *hashtab.offset(3);
            let bloomwords_ptr = hashtab.offset(4) as *const usize;
            let buckets_ptr = bloomwords_ptr.offset(maskwords as isize) as *const u32;
            let buckets = slice::from_raw_parts(buckets_ptr, nbuckets as usize);
            let hashvalues_ptr = buckets_ptr.offset(nbuckets as isize);
            let hashvalues = slice::from_raw_parts(hashvalues_ptr, total_dynsyms - symindex);
            let bloomwords = slice::from_raw_parts(bloomwords_ptr, maskwords);
            GnuHash {
                nbuckets: nbuckets,
                symindex: symindex,
                maskwords: maskwords,
                shift2: shift2,
                maskbits: 64, // because we don't have a compile time sizeof yet...
                bloomwords: bloomwords,
                hashvalues: hashvalues,
                buckets: buckets,
                maskwords_bitmask: ((maskwords as i32) - 1) as u32
            }
        }
    }

    #[inline(always)]
    fn lookup(&self, hash: u32, symbol: &str, bias: u64, strtab: &'process strtab::Strtab, symtab: &'process[sym::Sym]) -> Option<u64> {
        let mut idx = self.buckets[(hash % self.nbuckets) as usize] as usize;
        //println!("lookup idx = buckets[hash % nbuckets] = {}", idx);
        if idx == 0 { return None }
        let mut hash_idx = idx - self.symindex;
        let hash = hash & !1;
        // TODO: replace this with an iterator
        loop {
            let symbol_ = &symtab[idx];
            let h2 = self.hashvalues[hash_idx];
            idx += 1;
            hash_idx += 1;
            let name = &strtab[symbol_.st_name as usize];
            // println!("{}: h2 0x{:x} resolves to: {}", i, h2, name);
            if hash == (h2 & !1) && name == symbol {
                //println!("lookup match for {} at: 0x{:x}", symbol, symbol_.st_value);
                return Some(symbol_.st_value + bias)
            }
            if h2 & 1 == 1 { break } // end of chain
        }
        None
    }

    #[inline(always)]
    fn filter(&self, hash: u32) -> bool {
        let bloom_idx = (hash / self.maskbits) & self.maskwords_bitmask;
        let h2 = hash >> self.shift2;
        let bitmask = (1u64 << (hash % self.maskbits)) | (1u64 << (h2 % self.maskbits));
//        println!("lookup: maskwords: {} bloom_idx: {} bitmask: {} shift2: {}", self.maskwords, bloom_idx, bitmask, self.shift2);
        let filter = self.bloomwords[bloom_idx as usize];
        filter & (bitmask as usize) != (bitmask as usize) // if true, def _don't have_
    }

    /// Provide a name, a hash of that name, and the so to look in (which should have a reference to this self) -
    /// and we'll return an address option.
    pub fn find (&self, name: &str, hash: u32, so: &SharedObject) -> Option<u64> {
        if self.filter(hash) {
            None
        } else {
            self.lookup(hash, name, so.load_bias, &so.strtab, &so.symtab)
        }
    }
}
<|endoftext|>


<commit_before>use env;
use library::*;
use config::gobjects::GObject;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConversionType {
    Direct,  //coded without conversion
    Scalar,  //coded with from_glib
    Pointer, //coded with from_glib_xxx
    Borrow,  //same as Pointer, except that use from_glib_borrow instead from_glib_none
    Unknown,
}

impl Default for ConversionType {
    fn default() -> Self {
        ConversionType::Unknown
    }
}

impl ConversionType {
    pub fn of(env: &env::Env, type_id: TypeId) -> ConversionType {
        let library = &env.library;

        if let Some(&GObject {
            conversion_type: Some(conversion_type),
            ..
        }) = env.config.objects.get(&type_id.full_name(library))
        {
            return conversion_type;
        }

        use library::Type::*;
        use library::Fundamental::*;
        match *library.type_(type_id) {
            Fundamental(fund) => match fund {
                Boolean => ConversionType::Scalar,
                Int8 => ConversionType::Direct,
                UInt8 => ConversionType::Direct,
                Int16 => ConversionType::Direct,
                UInt16 => ConversionType::Direct,
                Int32 => ConversionType::Direct,
                UInt32 => ConversionType::Direct,
                Int64 => ConversionType::Direct,
                UInt64 => ConversionType::Direct,
                Char => ConversionType::Scalar,
                UChar => ConversionType::Scalar,
                Short => ConversionType::Direct,
                UShort => ConversionType::Direct,
                Int => ConversionType::Direct,
                UInt => ConversionType::Direct,
                Long => ConversionType::Direct,
                ULong => ConversionType::Direct,
                Size => ConversionType::Direct,
                SSize => ConversionType::Direct,
                Float => ConversionType::Direct,
                Double => ConversionType::Direct,
                UniChar => ConversionType::Scalar,
                Pointer => ConversionType::Pointer,
                VarArgs => ConversionType::Unknown,
                Utf8 => ConversionType::Pointer,
                Filename => ConversionType::Pointer,
                OsString => ConversionType::Pointer,
                Type => ConversionType::Scalar,
                None => ConversionType::Unknown,
                IntPtr => ConversionType::Direct,
                UIntPtr => ConversionType::Direct,
                Unsupported => ConversionType::Unknown,
            },
            Alias(ref alias) => ConversionType::of(env, alias.typ),
            Bitfield(_) => ConversionType::Scalar,
            Record(_) => ConversionType::Pointer,
            Union(_) => ConversionType::Pointer,
            Enumeration(_) => ConversionType::Scalar,
            Interface(_) => ConversionType::Pointer,
            Class(_) => ConversionType::Pointer,
            CArray(_) => ConversionType::Pointer,
            List(_) => ConversionType::Pointer,
            SList(_) => ConversionType::Pointer,
            Function(super::library::Function { ref name, .. }) if name == "AsyncReadyCallback" =>
                ConversionType::Direct,
            Custom(super::library::Custom {
                conversion_type, ..
            }) => conversion_type,
            _ => ConversionType::Unknown,
        }
    }
}
<commit_msg>Make ConversionType for glib::Quark Scalar<commit_after>use env;
use library::*;
use config::gobjects::GObject;

#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ConversionType {
    Direct,  //coded without conversion
    Scalar,  //coded with from_glib
    Pointer, //coded with from_glib_xxx
    Borrow,  //same as Pointer, except that use from_glib_borrow instead from_glib_none
    Unknown,
}

impl Default for ConversionType {
    fn default() -> Self {
        ConversionType::Unknown
    }
}

impl ConversionType {
    pub fn of(env: &env::Env, type_id: TypeId) -> ConversionType {
        let library = &env.library;

        if let Some(&GObject {
            conversion_type: Some(conversion_type),
            ..
        }) = env.config.objects.get(&type_id.full_name(library))
        {
            return conversion_type;
        }

        use library::Type::*;
        use library::Fundamental::*;
        match *library.type_(type_id) {
            Fundamental(fund) => match fund {
                Boolean => ConversionType::Scalar,
                Int8 => ConversionType::Direct,
                UInt8 => ConversionType::Direct,
                Int16 => ConversionType::Direct,
                UInt16 => ConversionType::Direct,
                Int32 => ConversionType::Direct,
                UInt32 => ConversionType::Direct,
                Int64 => ConversionType::Direct,
                UInt64 => ConversionType::Direct,
                Char => ConversionType::Scalar,
                UChar => ConversionType::Scalar,
                Short => ConversionType::Direct,
                UShort => ConversionType::Direct,
                Int => ConversionType::Direct,
                UInt => ConversionType::Direct,
                Long => ConversionType::Direct,
                ULong => ConversionType::Direct,
                Size => ConversionType::Direct,
                SSize => ConversionType::Direct,
                Float => ConversionType::Direct,
                Double => ConversionType::Direct,
                UniChar => ConversionType::Scalar,
                Pointer => ConversionType::Pointer,
                VarArgs => ConversionType::Unknown,
                Utf8 => ConversionType::Pointer,
                Filename => ConversionType::Pointer,
                OsString => ConversionType::Pointer,
                Type => ConversionType::Scalar,
                None => ConversionType::Unknown,
                IntPtr => ConversionType::Direct,
                UIntPtr => ConversionType::Direct,
                Unsupported => ConversionType::Unknown,
            },
            Alias(ref alias) if alias.c_identifier == "GQuark" => ConversionType::Scalar,
            Alias(ref alias) => ConversionType::of(env, alias.typ),
            Bitfield(_) => ConversionType::Scalar,
            Record(_) => ConversionType::Pointer,
            Union(_) => ConversionType::Pointer,
            Enumeration(_) => ConversionType::Scalar,
            Interface(_) => ConversionType::Pointer,
            Class(_) => ConversionType::Pointer,
            CArray(_) => ConversionType::Pointer,
            List(_) => ConversionType::Pointer,
            SList(_) => ConversionType::Pointer,
            Function(super::library::Function { ref name, .. }) if name == "AsyncReadyCallback" =>
                ConversionType::Direct,
            Custom(super::library::Custom {
                conversion_type, ..
            }) => conversion_type,
            _ => ConversionType::Unknown,
        }
    }
}
<|endoftext|>


<commit_before>use crypto::md5::Md5;
use crypto::digest::Digest;
use std::collections::HashMap;
use std::collections::BinaryHeap;

// As a convenience, rust-hash-ring provides a defaul struct to hold node
// information. It is optional and you can define yours.
#[derive(Clone)]
pub struct NodeInfo {
	pub host: &'static str,
	pub port: u16
}

impl ToString for NodeInfo {
	fn to_string(&self) -> String {
		format!("{}:{}", self.host, self.port)
	}
}

pub struct HashRing<T> {
	replicas: isize,
	ring: HashMap<String, T>,
	sorted_keys: Vec<String>
}

impl<T: ToString+Clone> HashRing<T> {
	/// Creates a new hash ring with the specified nodes. Replicas is the number of virtual nodes each node has to make a better distribution.
	pub fn new(nodes: Vec<T>, replicas: isize) -> HashRing<T> {
		let mut new_hash_ring: HashRing<T> = HashRing {
			replicas: replicas,
			ring: HashMap::new(),
			sorted_keys: Vec::new()
		};

		for i in 0..nodes.len() {
			let n = &nodes[i];
			new_hash_ring.add_node(n);
		}
		return new_hash_ring;
	}

	/// Adds a node to the hash ring
	pub fn add_node(&mut self, node: &T) {
		for i in 0..self.replicas {
			let key = self.gen_key(format!("{}:{}", node.to_string(), i));
			self.ring.insert(key.clone(), (*node).clone());
			self.sorted_keys.push(key.clone());
		}

		self.sorted_keys = BinaryHeap::from(self.sorted_keys.clone()).into_sorted_vec();
	}

	/// Deletes a node from the hash ring
	pub fn remove_node(&mut self, node: &T) {
		for i in 0..self.replicas {
			let key = self.gen_key(format!("{}:{}", node.to_string(), i));
			self.ring.remove(&key);
			let mut index = 0;
			for j in 0..self.sorted_keys.len() {
				if self.sorted_keys[j] == key {
					index = j;
					break;
				}
			}
			self.sorted_keys.remove(index);
		}
	}

	/// Gets the node a specific key belongs to
	pub fn get_node(&mut self, key: String) -> Option<&T> {
		if self.sorted_keys.is_empty() {
			return None;
		}

		let generated_key = self.gen_key(key);
		let nodes = self.sorted_keys.clone();

		for i in 0..nodes.len() {
			let node = &nodes[i];
			if generated_key <= *node {
				return Some(self.ring.get(node).unwrap());
			}
		}

		let node = &nodes[0];
		return Some(self.ring.get(node).unwrap());
	}

	/// Generates a key from a string value
	fn gen_key(&mut self, key: String) -> String {
		let mut md5: Md5 = Md5::new();
		md5.input_str(key.as_ref());
		return md5.result_str();
	}
}

#[cfg(test)]
mod test {
	use hash_ring::{NodeInfo, HashRing};

	#[test]
	fn test_empty_ring() {
		let mut hash_ring: HashRing<NodeInfo> = HashRing::new(vec![], 10);
		assert_eq!(None, hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
	}

	#[test]
	fn test_default_nodes() {
		let mut nodes: Vec<NodeInfo> = Vec::new();
		nodes.push(NodeInfo{host: "localhost", port: 15324});
		nodes.push(NodeInfo{host: "localhost", port: 15325});
		nodes.push(NodeInfo{host: "localhost", port: 15326});
		nodes.push(NodeInfo{host: "localhost", port: 15327});
		nodes.push(NodeInfo{host: "localhost", port: 15328});
		nodes.push(NodeInfo{host: "localhost", port: 15329});

		let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
		assert_eq!(Some("localhost:15326".to_string()), hash_ring.get_node("dude".to_string()).map(|x| x.to_string()));

		hash_ring.remove_node(&NodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15327".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

		hash_ring.add_node(&NodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

	}

	#[derive(Clone)]
	struct CustomNodeInfo {
		pub host: &'static str,
		pub port: u16
	}

	impl ToString for CustomNodeInfo {
		fn to_string(&self) -> String {
			format!("{}:{}", self.host, self.port)
		}
	}

	#[test]
	fn test_custom_nodes() {

		let mut nodes: Vec<CustomNodeInfo> = Vec::new();
		nodes.push(CustomNodeInfo{host: "localhost", port: 15324});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15325});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15326});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15327});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15328});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15329});

		let mut hash_ring: HashRing<CustomNodeInfo> = HashRing::new(nodes, 10);

		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
		assert_eq!(Some("localhost:15326".to_string()), hash_ring.get_node("dude".to_string()).map(|x| x.to_string()));

		hash_ring.remove_node(&CustomNodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15327".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

		hash_ring.add_node(&CustomNodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

	}
}
<commit_msg>Fixing some simple spelling mistakes<commit_after>use crypto::md5::Md5;
use crypto::digest::Digest;
use std::collections::HashMap;
use std::collections::BinaryHeap;

/// As a convenience, rust-hash-ring provides a default struct to hold node
/// information. It is optional and you can define your own.
#[derive(Clone)]
pub struct NodeInfo {
	pub host: &'static str,
	pub port: u16
}

impl ToString for NodeInfo {
	fn to_string(&self) -> String {
		format!("{}:{}", self.host, self.port)
	}
}

/// HashRing
pub struct HashRing<T> {
	replicas: isize,
	ring: HashMap<String, T>,
	sorted_keys: Vec<String>
}

impl<T: ToString+Clone> HashRing<T> {
	/// Creates a new hash ring with the specified nodes. Replicas is the number of virtual nodes each node has to make a better distribution.
	pub fn new(nodes: Vec<T>, replicas: isize) -> HashRing<T> {
		let mut new_hash_ring: HashRing<T> = HashRing {
			replicas: replicas,
			ring: HashMap::new(),
			sorted_keys: Vec::new()
		};

		for i in 0..nodes.len() {
			let n = &nodes[i];
			new_hash_ring.add_node(n);
		}
		return new_hash_ring;
	}

	/// Adds a node to the hash ring
	pub fn add_node(&mut self, node: &T) {
		for i in 0..self.replicas {
			let key = self.gen_key(format!("{}:{}", node.to_string(), i));
			self.ring.insert(key.clone(), (*node).clone());
			self.sorted_keys.push(key.clone());
		}

		self.sorted_keys = BinaryHeap::from(self.sorted_keys.clone()).into_sorted_vec();
	}

	/// Deletes a node from the hash ring
	pub fn remove_node(&mut self, node: &T) {
		for i in 0..self.replicas {
			let key = self.gen_key(format!("{}:{}", node.to_string(), i));
			self.ring.remove(&key);
			let mut index = 0;
			for j in 0..self.sorted_keys.len() {
				if self.sorted_keys[j] == key {
					index = j;
					break;
				}
			}
			self.sorted_keys.remove(index);
		}
	}

	/// Gets the node a specific key belongs to
	pub fn get_node(&mut self, key: String) -> Option<&T> {
		if self.sorted_keys.is_empty() {
			return None;
		}

		let generated_key = self.gen_key(key);
		let nodes = self.sorted_keys.clone();

		for i in 0..nodes.len() {
			let node = &nodes[i];
			if generated_key <= *node {
				return Some(self.ring.get(node).unwrap());
			}
		}

		let node = &nodes[0];
		return Some(self.ring.get(node).unwrap());
	}

	/// Generates a key from a string value
	fn gen_key(&mut self, key: String) -> String {
		let mut md5: Md5 = Md5::new();
		md5.input_str(key.as_ref());
		return md5.result_str();
	}
}

#[cfg(test)]
mod test {
	use hash_ring::{NodeInfo, HashRing};

	#[test]
	fn test_empty_ring() {
		let mut hash_ring: HashRing<NodeInfo> = HashRing::new(vec![], 10);
		assert_eq!(None, hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
	}

	#[test]
	fn test_default_nodes() {
		let mut nodes: Vec<NodeInfo> = Vec::new();
		nodes.push(NodeInfo{host: "localhost", port: 15324});
		nodes.push(NodeInfo{host: "localhost", port: 15325});
		nodes.push(NodeInfo{host: "localhost", port: 15326});
		nodes.push(NodeInfo{host: "localhost", port: 15327});
		nodes.push(NodeInfo{host: "localhost", port: 15328});
		nodes.push(NodeInfo{host: "localhost", port: 15329});

		let mut hash_ring: HashRing<NodeInfo> = HashRing::new(nodes, 10);

		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
		assert_eq!(Some("localhost:15326".to_string()), hash_ring.get_node("dude".to_string()).map(|x| x.to_string()));

		hash_ring.remove_node(&NodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15327".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

		hash_ring.add_node(&NodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

	}

	#[derive(Clone)]
	struct CustomNodeInfo {
		pub host: &'static str,
		pub port: u16
	}

	impl ToString for CustomNodeInfo {
		fn to_string(&self) -> String {
			format!("{}:{}", self.host, self.port)
		}
	}

	#[test]
	fn test_custom_nodes() {

		let mut nodes: Vec<CustomNodeInfo> = Vec::new();
		nodes.push(CustomNodeInfo{host: "localhost", port: 15324});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15325});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15326});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15327});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15328});
		nodes.push(CustomNodeInfo{host: "localhost", port: 15329});

		let mut hash_ring: HashRing<CustomNodeInfo> = HashRing::new(nodes, 10);

		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));
		assert_eq!(Some("localhost:15326".to_string()), hash_ring.get_node("dude".to_string()).map(|x| x.to_string()));

		hash_ring.remove_node(&CustomNodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15327".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

		hash_ring.add_node(&CustomNodeInfo{host: "localhost", port: 15329});
		assert_eq!(Some("localhost:15329".to_string()), hash_ring.get_node("hello".to_string()).map(|x| x.to_string()));

	}
}
<|endoftext|>


<commit_before>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);
}

pub struct Heartbeat {
    pub hb: *mut c_void,
}

impl Heartbeat {
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: &str,
               energy_impl: &mut EnergyMon) -> Result<Heartbeat, String> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth,
                                   CString::new(log_name).unwrap().as_ptr(),
                                   1, energy_impl)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat".to_string());
        }
        Ok(Heartbeat { hb: heart, })
    }

    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }
}

impl Drop for Heartbeat {
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

<commit_msg>Accept Option for EnergyMon; add simple test<commit_after>use libc::{uint64_t, int64_t, c_void, c_char, c_double};
use std::ffi::CString;
use std::ptr;
use energymon_sys::energymon::EnergyMon;

#[link(name = "hbt-acc-pow")]
extern {
    fn heartbeat_acc_pow_init(parent: *mut c_void,
                              window_size: uint64_t,
                              buffer_depth: uint64_t,
                              log_name: *const c_char,
                              num_energy_impls: uint64_t,
                              energy_impls: *mut EnergyMon) -> *mut c_void;

    fn heartbeat_acc(hb: *mut c_void,
                     user_tag: uint64_t,
                     work: uint64_t,
                     accuracy: c_double,
                     hb_prev: *mut c_void) -> int64_t;

    fn heartbeat_finish(hb: *mut c_void);
}

pub struct Heartbeat {
    pub hb: *mut c_void,
}

impl Heartbeat {
    pub fn new(parent: Option<&mut Heartbeat>,
               window_size: u64,
               buffer_depth: u64,
               log_name: &str,
               energy_impl: Option<&mut EnergyMon>) -> Result<Heartbeat, String> {
        let parent = match parent {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        let num_energy_impls: u64;
        let mut em: *mut EnergyMon;
        if energy_impl.is_some() {
            num_energy_impls = 1;
            em = energy_impl.unwrap();
        } else {
            num_energy_impls = 0;
            em = ptr::null_mut();
        }
        let heart = unsafe {
            heartbeat_acc_pow_init(parent, window_size, buffer_depth,
                                   CString::new(log_name).unwrap().as_ptr(),
                                   num_energy_impls, em)
        };
        if heart.is_null() {
            return Err("Failed to initialize heartbeat".to_string());
        }
        Ok(Heartbeat { hb: heart, })
    }

    pub fn heartbeat(&mut self,
                     tag: u64,
                     work: u64,
                     accuracy: f64,
                     hb_prev: Option<&Heartbeat>) -> i64 {
        let hb_prev = match hb_prev {
            Some(p) => p.hb,
            None => ptr::null_mut(),
        };
        unsafe {
            heartbeat_acc(self.hb, tag, work, accuracy, hb_prev)
        }
    }
}

impl Drop for Heartbeat {
    fn drop(&mut self) {
        unsafe {
            heartbeat_finish(self.hb);
        }
    }
}

#[test]
fn test_no_energymon() {
    let mut hb = Heartbeat::new(None, 20, 20, "heartbeat.log", None).unwrap();
    hb.heartbeat(0, 1, 0.0, None);
}
<|endoftext|>


<commit_before>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    fat_type::{FatStructType, FatType},
    resolver::Resolver,
};
use anyhow::{anyhow, bail, Result};
use diem_state_view::StateView;
use diem_types::{
    access_path::AccessPath, account_address::AccountAddress, account_state::AccountState,
    contract_event::ContractEvent,
};
use move_core_types::{
    identifier::Identifier,
    language_storage::{ModuleId, StructTag},
    value::{MoveStruct, MoveValue},
};
use move_vm_runtime::data_cache::RemoteCache;
use std::{
    collections::btree_map::BTreeMap,
    convert::TryInto,
    fmt::{Display, Formatter},
};
use vm::errors::{Location, PartialVMError, PartialVMResult, VMResult};

mod fat_type;
mod module_cache;
mod resolver;

#[derive(Debug)]
pub struct AnnotatedAccountStateBlob(BTreeMap<StructTag, AnnotatedMoveStruct>);

#[derive(Debug)]
pub struct AnnotatedMoveStruct {
    pub is_resource: bool,
    pub type_: StructTag,
    pub value: Vec<(Identifier, AnnotatedMoveValue)>,
}

/// AnnotatedMoveValue is a fully expanded version of on chain Move data. This should only be used
/// for debugging/client purpose right now and just for a better visualization of on chain data. In
/// the long run, we would like to transform this struct to a Json value so that we can have a cross
/// platform interpretation of the on chain data.
#[derive(Debug)]
pub enum AnnotatedMoveValue {
    U8(u8),
    U64(u64),
    U128(u128),
    Bool(bool),
    Address(AccountAddress),
    Vector(Vec<AnnotatedMoveValue>),
    Bytes(Vec<u8>),
    Struct(AnnotatedMoveStruct),
}

pub struct MoveValueAnnotator<'a> {
    cache: Resolver<'a>,
    _data_view: &'a dyn RemoteCache,
}

impl<'a> MoveValueAnnotator<'a> {
    pub fn new(view: &'a dyn RemoteCache) -> Self {
        Self {
            cache: Resolver::new(view, true),
            _data_view: view,
        }
    }

    pub fn new_no_stdlib(view: &'a dyn RemoteCache) -> Self {
        Self {
            cache: Resolver::new(view, false),
            _data_view: view,
        }
    }

    pub fn view_access_path(
        &self,
        access_path: AccessPath,
        blob: &[u8],
    ) -> Result<AnnotatedMoveStruct> {
        match access_path.get_struct_tag() {
            Some(tag) => self.view_resource(&tag, blob),
            None => bail!("Bad resource access path"),
        }
    }

    pub fn view_resource(&self, tag: &StructTag, blob: &[u8]) -> Result<AnnotatedMoveStruct> {
        let ty = self.cache.resolve_struct(tag)?;
        let struct_def = (&ty)
            .try_into()
            .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;
        let move_struct = MoveStruct::simple_deserialize(blob, &struct_def)?;
        self.annotate_struct(&move_struct, &ty)
    }

    pub fn view_contract_event(&self, event: &ContractEvent) -> Result<AnnotatedMoveValue> {
        let ty = self.cache.resolve_type(event.type_tag())?;
        let move_ty = (&ty)
            .try_into()
            .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;

        let move_value = MoveValue::simple_deserialize(event.event_data(), &move_ty)?;
        self.annotate_value(&move_value, &ty)
    }

    pub fn view_account_state(&self, state: &AccountState) -> Result<AnnotatedAccountStateBlob> {
        let mut output = BTreeMap::new();
        for (k, v) in state.iter() {
            let tag = match AccessPath::new(AccountAddress::random(), k.to_vec()).get_struct_tag() {
                Some(t) => t,
                None => {
                    println!("Uncached AccessPath: {:?}", k);
                    continue;
                }
            };
            let ty = self.cache.resolve_struct(&tag)?;
            let struct_def = (&ty)
                .try_into()
                .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;

            let move_struct = MoveStruct::simple_deserialize(v.as_slice(), &struct_def)?;
            output.insert(
                ty.struct_tag()
                    .map_err(|e| e.finish(Location::Undefined).into_vm_status())
                    .unwrap(),
                self.annotate_struct(&move_struct, &ty)?,
            );
        }
        Ok(AnnotatedAccountStateBlob(output))
    }

    fn annotate_struct(
        &self,
        move_struct: &MoveStruct,
        ty: &FatStructType,
    ) -> Result<AnnotatedMoveStruct> {
        let struct_tag = ty
            .struct_tag()
            .map_err(|e| e.finish(Location::Undefined).into_vm_status())?;
        let field_names = self.cache.get_field_names(ty)?;
        let mut annotated_fields = vec![];
        for (ty, v) in ty.layout.iter().zip(move_struct.fields().iter()) {
            annotated_fields.push(self.annotate_value(v, ty)?);
        }
        Ok(AnnotatedMoveStruct {
            is_resource: ty.is_resource,
            type_: struct_tag,
            value: field_names
                .into_iter()
                .zip(annotated_fields.into_iter())
                .collect(),
        })
    }

    fn annotate_value(&self, value: &MoveValue, ty: &FatType) -> Result<AnnotatedMoveValue> {
        Ok(match (value, ty) {
            (MoveValue::Bool(b), FatType::Bool) => AnnotatedMoveValue::Bool(*b),
            (MoveValue::U8(i), FatType::U8) => AnnotatedMoveValue::U8(*i),
            (MoveValue::U64(i), FatType::U64) => AnnotatedMoveValue::U64(*i),
            (MoveValue::U128(i), FatType::U128) => AnnotatedMoveValue::U128(*i),
            (MoveValue::Address(a), FatType::Address) => AnnotatedMoveValue::Address(*a),
            (MoveValue::Vector(a), FatType::Vector(ty)) => match ty.as_ref() {
                FatType::U8 => AnnotatedMoveValue::Bytes(
                    a.iter()
                        .map(|v| match v {
                            MoveValue::U8(i) => Ok(*i),
                            _ => Err(anyhow!("unexpected value type")),
                        })
                        .collect::<Result<_>>()?,
                ),
                _ => AnnotatedMoveValue::Vector(
                    a.iter()
                        .map(|v| self.annotate_value(v, ty.as_ref()))
                        .collect::<Result<_>>()?,
                ),
            },
            (MoveValue::Struct(s), FatType::Struct(ty)) => {
                AnnotatedMoveValue::Struct(self.annotate_struct(s, ty.as_ref())?)
            }
            _ => {
                return Err(anyhow!(
                    "Cannot annotate value {:?} with type {:?}",
                    value,
                    ty
                ))
            }
        })
    }
}

fn write_indent(f: &mut Formatter, indent: u64) -> std::fmt::Result {
    for _i in 0..indent {
        write!(f, " ")?;
    }
    Ok(())
}

fn pretty_print_value(
    f: &mut Formatter,
    value: &AnnotatedMoveValue,
    indent: u64,
) -> std::fmt::Result {
    match value {
        AnnotatedMoveValue::Bool(b) => write!(f, "{}", b),
        AnnotatedMoveValue::U8(v) => write!(f, "{}u8", v),
        AnnotatedMoveValue::U64(v) => write!(f, "{}", v),
        AnnotatedMoveValue::U128(v) => write!(f, "{}u128", v),
        AnnotatedMoveValue::Address(a) => write!(f, "{}", a.short_str_lossless()),
        AnnotatedMoveValue::Vector(v) => {
            writeln!(f, "[")?;
            for value in v.iter() {
                write_indent(f, indent + 4)?;
                pretty_print_value(f, value, indent + 4)?;
                writeln!(f, ",")?;
            }
            write_indent(f, indent)?;
            write!(f, "]")
        }
        AnnotatedMoveValue::Bytes(v) => write!(f, "{}", hex::encode(&v)),
        AnnotatedMoveValue::Struct(s) => pretty_print_struct(f, s, indent),
    }
}

fn pretty_print_struct(
    f: &mut Formatter,
    value: &AnnotatedMoveStruct,
    indent: u64,
) -> std::fmt::Result {
    writeln!(
        f,
        "{}{} {{",
        if value.is_resource { "resource " } else { "" },
        value.type_
    )?;
    for (field_name, v) in value.value.iter() {
        write_indent(f, indent + 4)?;
        write!(f, "{}: ", field_name)?;
        pretty_print_value(f, v, indent + 4)?;
        writeln!(f)?;
    }
    write_indent(f, indent)?;
    write!(f, "}}")
}

impl Display for AnnotatedMoveValue {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        pretty_print_value(f, self, 0)
    }
}

impl Display for AnnotatedMoveStruct {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        pretty_print_struct(f, self, 0)
    }
}

impl Display for AnnotatedAccountStateBlob {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        writeln!(f, "{{")?;
        for v in self.0.values() {
            write!(f, "{}", v)?;
            writeln!(f, ",")?;
        }
        writeln!(f, "}}")
    }
}

#[derive(Default)]
pub struct NullStateView();

impl StateView for NullStateView {
    fn get(&self, _access_path: &AccessPath) -> Result<Option<Vec<u8>>> {
        Err(anyhow!("No data"))
    }

    fn multi_get(&self, _access_paths: &[AccessPath]) -> Result<Vec<Option<Vec<u8>>>> {
        Err(anyhow!("No data"))
    }

    fn is_genesis(&self) -> bool {
        false
    }
}

impl RemoteCache for NullStateView {
    fn get_module(&self, _module_id: &ModuleId) -> VMResult<Option<Vec<u8>>> {
        Ok(None)
    }

    fn get_resource(
        &self,
        _address: &AccountAddress,
        _tag: &StructTag,
    ) -> PartialVMResult<Option<Vec<u8>>> {
        Ok(None)
    }
}
<commit_msg>[resource-viewer] Store TypeTag with Vectors in AnnotatedMoveValue<commit_after>// Copyright (c) The Diem Core Contributors
// SPDX-License-Identifier: Apache-2.0

use crate::{
    fat_type::{FatStructType, FatType},
    resolver::Resolver,
};
use anyhow::{anyhow, bail, Result};
use diem_state_view::StateView;
use diem_types::{
    access_path::AccessPath, account_address::AccountAddress, account_state::AccountState,
    contract_event::ContractEvent,
};
use move_core_types::{
    identifier::Identifier,
    language_storage::{ModuleId, StructTag, TypeTag},
    value::{MoveStruct, MoveValue},
};
use move_vm_runtime::data_cache::RemoteCache;
use std::{
    collections::btree_map::BTreeMap,
    convert::TryInto,
    fmt::{Display, Formatter},
};
use vm::errors::{Location, PartialVMError, PartialVMResult, VMResult};

mod fat_type;
mod module_cache;
mod resolver;

#[derive(Debug)]
pub struct AnnotatedAccountStateBlob(BTreeMap<StructTag, AnnotatedMoveStruct>);

#[derive(Debug)]
pub struct AnnotatedMoveStruct {
    pub is_resource: bool,
    pub type_: StructTag,
    pub value: Vec<(Identifier, AnnotatedMoveValue)>,
}

/// AnnotatedMoveValue is a fully expanded version of on chain Move data. This should only be used
/// for debugging/client purpose right now and just for a better visualization of on chain data. In
/// the long run, we would like to transform this struct to a Json value so that we can have a cross
/// platform interpretation of the on chain data.
#[derive(Debug)]
pub enum AnnotatedMoveValue {
    U8(u8),
    U64(u64),
    U128(u128),
    Bool(bool),
    Address(AccountAddress),
    Vector(TypeTag, Vec<AnnotatedMoveValue>),
    Bytes(Vec<u8>),
    Struct(AnnotatedMoveStruct),
}

pub struct MoveValueAnnotator<'a> {
    cache: Resolver<'a>,
    _data_view: &'a dyn RemoteCache,
}

impl<'a> MoveValueAnnotator<'a> {
    pub fn new(view: &'a dyn RemoteCache) -> Self {
        Self {
            cache: Resolver::new(view, true),
            _data_view: view,
        }
    }

    pub fn new_no_stdlib(view: &'a dyn RemoteCache) -> Self {
        Self {
            cache: Resolver::new(view, false),
            _data_view: view,
        }
    }

    pub fn view_access_path(
        &self,
        access_path: AccessPath,
        blob: &[u8],
    ) -> Result<AnnotatedMoveStruct> {
        match access_path.get_struct_tag() {
            Some(tag) => self.view_resource(&tag, blob),
            None => bail!("Bad resource access path"),
        }
    }

    pub fn view_resource(&self, tag: &StructTag, blob: &[u8]) -> Result<AnnotatedMoveStruct> {
        let ty = self.cache.resolve_struct(tag)?;
        let struct_def = (&ty)
            .try_into()
            .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;
        let move_struct = MoveStruct::simple_deserialize(blob, &struct_def)?;
        self.annotate_struct(&move_struct, &ty)
    }

    pub fn view_contract_event(&self, event: &ContractEvent) -> Result<AnnotatedMoveValue> {
        let ty = self.cache.resolve_type(event.type_tag())?;
        let move_ty = (&ty)
            .try_into()
            .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;

        let move_value = MoveValue::simple_deserialize(event.event_data(), &move_ty)?;
        self.annotate_value(&move_value, &ty)
    }

    pub fn view_account_state(&self, state: &AccountState) -> Result<AnnotatedAccountStateBlob> {
        let mut output = BTreeMap::new();
        for (k, v) in state.iter() {
            let tag = match AccessPath::new(AccountAddress::random(), k.to_vec()).get_struct_tag() {
                Some(t) => t,
                None => {
                    println!("Uncached AccessPath: {:?}", k);
                    continue;
                }
            };
            let ty = self.cache.resolve_struct(&tag)?;
            let struct_def = (&ty)
                .try_into()
                .map_err(|e: PartialVMError| e.finish(Location::Undefined).into_vm_status())?;

            let move_struct = MoveStruct::simple_deserialize(v.as_slice(), &struct_def)?;
            output.insert(
                ty.struct_tag()
                    .map_err(|e| e.finish(Location::Undefined).into_vm_status())
                    .unwrap(),
                self.annotate_struct(&move_struct, &ty)?,
            );
        }
        Ok(AnnotatedAccountStateBlob(output))
    }

    fn annotate_struct(
        &self,
        move_struct: &MoveStruct,
        ty: &FatStructType,
    ) -> Result<AnnotatedMoveStruct> {
        let struct_tag = ty
            .struct_tag()
            .map_err(|e| e.finish(Location::Undefined).into_vm_status())?;
        let field_names = self.cache.get_field_names(ty)?;
        let mut annotated_fields = vec![];
        for (ty, v) in ty.layout.iter().zip(move_struct.fields().iter()) {
            annotated_fields.push(self.annotate_value(v, ty)?);
        }
        Ok(AnnotatedMoveStruct {
            is_resource: ty.is_resource,
            type_: struct_tag,
            value: field_names
                .into_iter()
                .zip(annotated_fields.into_iter())
                .collect(),
        })
    }

    fn annotate_value(&self, value: &MoveValue, ty: &FatType) -> Result<AnnotatedMoveValue> {
        Ok(match (value, ty) {
            (MoveValue::Bool(b), FatType::Bool) => AnnotatedMoveValue::Bool(*b),
            (MoveValue::U8(i), FatType::U8) => AnnotatedMoveValue::U8(*i),
            (MoveValue::U64(i), FatType::U64) => AnnotatedMoveValue::U64(*i),
            (MoveValue::U128(i), FatType::U128) => AnnotatedMoveValue::U128(*i),
            (MoveValue::Address(a), FatType::Address) => AnnotatedMoveValue::Address(*a),
            (MoveValue::Vector(a), FatType::Vector(ty)) => match ty.as_ref() {
                FatType::U8 => AnnotatedMoveValue::Bytes(
                    a.iter()
                        .map(|v| match v {
                            MoveValue::U8(i) => Ok(*i),
                            _ => Err(anyhow!("unexpected value type")),
                        })
                        .collect::<Result<_>>()?,
                ),
                _ => AnnotatedMoveValue::Vector(
                    ty.type_tag().unwrap(),
                    a.iter()
                        .map(|v| self.annotate_value(v, ty.as_ref()))
                        .collect::<Result<_>>()?,
                ),
            },
            (MoveValue::Struct(s), FatType::Struct(ty)) => {
                AnnotatedMoveValue::Struct(self.annotate_struct(s, ty.as_ref())?)
            }
            _ => {
                return Err(anyhow!(
                    "Cannot annotate value {:?} with type {:?}",
                    value,
                    ty
                ))
            }
        })
    }
}

fn write_indent(f: &mut Formatter, indent: u64) -> std::fmt::Result {
    for _i in 0..indent {
        write!(f, " ")?;
    }
    Ok(())
}

fn pretty_print_value(
    f: &mut Formatter,
    value: &AnnotatedMoveValue,
    indent: u64,
) -> std::fmt::Result {
    match value {
        AnnotatedMoveValue::Bool(b) => write!(f, "{}", b),
        AnnotatedMoveValue::U8(v) => write!(f, "{}u8", v),
        AnnotatedMoveValue::U64(v) => write!(f, "{}", v),
        AnnotatedMoveValue::U128(v) => write!(f, "{}u128", v),
        AnnotatedMoveValue::Address(a) => write!(f, "{}", a.short_str_lossless()),
        AnnotatedMoveValue::Vector(_, v) => {
            writeln!(f, "[")?;
            for value in v.iter() {
                write_indent(f, indent + 4)?;
                pretty_print_value(f, value, indent + 4)?;
                writeln!(f, ",")?;
            }
            write_indent(f, indent)?;
            write!(f, "]")
        }
        AnnotatedMoveValue::Bytes(v) => write!(f, "{}", hex::encode(&v)),
        AnnotatedMoveValue::Struct(s) => pretty_print_struct(f, s, indent),
    }
}

fn pretty_print_struct(
    f: &mut Formatter,
    value: &AnnotatedMoveStruct,
    indent: u64,
) -> std::fmt::Result {
    writeln!(
        f,
        "{}{} {{",
        if value.is_resource { "resource " } else { "" },
        value.type_
    )?;
    for (field_name, v) in value.value.iter() {
        write_indent(f, indent + 4)?;
        write!(f, "{}: ", field_name)?;
        pretty_print_value(f, v, indent + 4)?;
        writeln!(f)?;
    }
    write_indent(f, indent)?;
    write!(f, "}}")
}

impl Display for AnnotatedMoveValue {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        pretty_print_value(f, self, 0)
    }
}

impl Display for AnnotatedMoveStruct {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        pretty_print_struct(f, self, 0)
    }
}

impl Display for AnnotatedAccountStateBlob {
    fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
        writeln!(f, "{{")?;
        for v in self.0.values() {
            write!(f, "{}", v)?;
            writeln!(f, ",")?;
        }
        writeln!(f, "}}")
    }
}

#[derive(Default)]
pub struct NullStateView();

impl StateView for NullStateView {
    fn get(&self, _access_path: &AccessPath) -> Result<Option<Vec<u8>>> {
        Err(anyhow!("No data"))
    }

    fn multi_get(&self, _access_paths: &[AccessPath]) -> Result<Vec<Option<Vec<u8>>>> {
        Err(anyhow!("No data"))
    }

    fn is_genesis(&self) -> bool {
        false
    }
}

impl RemoteCache for NullStateView {
    fn get_module(&self, _module_id: &ModuleId) -> VMResult<Option<Vec<u8>>> {
        Ok(None)
    }

    fn get_resource(
        &self,
        _address: &AccountAddress,
        _tag: &StructTag,
    ) -> PartialVMResult<Option<Vec<u8>>> {
        Ok(None)
    }
}
<|endoftext|>


<commit_before>use oppai_common::common::is_last_move_stupid;
use oppai_common::trajectory::{build_trajectories, build_trajectories_from, Trajectory};
use oppai_field::field::wave_diag;
use oppai_field::field::{Field, NonZeroPos, Pos};
use oppai_field::player::Player;
use std::iter;
use std::sync::atomic::{AtomicBool, Ordering};

fn mark_group(field: &Field, start_pos: Pos, player: Player, empty_board: &mut Vec<u32>) -> Vec<Pos> {
  let mut marks = Vec::new();
  wave_diag(field.width(), start_pos, |pos| {
    if empty_board[pos] != 0 {
      return false;
    }
    let cell = field.cell(pos);
    if cell.is_players_point(player) {
      empty_board[pos] = 1;
      marks.push(pos);
      true
    } else {
      false
    }
  });
  marks
}

fn is_trajectoty_alive(field: &mut Field, trajectory: &Trajectory, player: Player) -> bool {
  if trajectory.points().iter().any(|&pos| !field.is_putting_allowed(pos)) {
    return false;
  }

  for &pos in trajectory.points() {
    field.put_point(pos, player);
  }

  let result = field.get_delta_score(player) > 0
    || (field.min_pos()..field.max_pos()).any(|pos| {
      field.is_putting_allowed(pos) && {
        field.put_point(pos, player);
        let result = field.get_delta_score(player) > 0
          && trajectory
            .points()
            .iter()
            .all(|&trajectory_pos| field.cell(trajectory_pos).is_bound());
        field.undo();
        result && {
          let enemy = player.next();
          let enemies_around = field
            .directions(pos)
            .iter()
            .filter(|&&pos| field.cell(pos).is_players_point(enemy))
            .count();
          enemies_around < 3
            || enemies_around == 3
              && field
                .directions(pos)
                .iter()
                .all(|&near_pos| !field.cell(near_pos).is_putting_allowed())
        }
      }
    });

  for _ in 0..trajectory.len() {
    field.undo();
  }

  result
}

fn is_trajectoty_viable(field: &mut Field, trajectory: &Trajectory, player: Player) -> bool {
  let enemy = player.next();
  (field.min_pos()..field.max_pos()).all(|enemy_pos| {
    !field.is_putting_allowed(enemy_pos) || {
      field.put_point(enemy_pos, enemy);

      if field.get_delta_score(enemy) == 0 {
        field.undo();
        return true;
      }

      let result = is_trajectoty_alive(field, trajectory, player);

      field.undo();

      result
    }
  })
}

fn ladders_rec(
  field: &mut Field,
  player: Player,
  trajectory: &Trajectory,
  empty_board: &mut Vec<u32>,
  should_stop: &AtomicBool,
  depth: u32,
) -> (Option<NonZeroPos>, i32, u32, u32) {
  match *trajectory.points().as_slice() {
    [pos] => {
      field.put_point(pos, player);
      let cur_score = field.score(player);
      field.undo();
      (NonZeroPos::new(pos), cur_score, depth, depth)
    }
    [pos1, pos2] => {
      let mut max_score = field.score(player);
      let mut best_move = None;
      let mut max_depth = depth;
      let mut capture_depth = 0;

      for &(our_pos, enemy_pos) in &[(pos1, pos2), (pos2, pos1)] {
        if trajectory.score() <= max_score {
          break;
        }

        if field.cell(our_pos).is_players_empty_base(player.next()) {
          continue;
        }

        if !field.put_point(our_pos, player) {
          panic!(
            "Failed to put a point to ({}, {}) on the field:\n{}",
            field.to_x(our_pos),
            field.to_y(our_pos),
            field,
          );
        }

        if is_last_move_stupid(field, our_pos, player) {
          field.undo();
          continue;
        }

        if field.get_delta_score(player) > 0 {
          let cur_score = field.score(player);
          field.undo();
          if cur_score > max_score {
            max_score = cur_score;
            best_move = NonZeroPos::new(our_pos);
            capture_depth = depth;
          }
          continue;
        }

        if !field.put_point(enemy_pos, player.next()) {
          panic!(
            "Failed to put a point to ({}, {}) on the field:\n{}",
            field.to_x(our_pos),
            field.to_y(our_pos),
            field,
          );
        }

        let trajectories = build_trajectories_from(field, our_pos, player, 2, empty_board, should_stop);

        if should_stop.load(Ordering::Relaxed) {
          break;
        }

        let marks = mark_group(field, our_pos, player, empty_board);

        for trajectory in trajectories {
          if trajectory.score() <= max_score {
            continue;
          }

          let (_, cur_score, cur_depth, cur_capture_depth) =
            ladders_rec(field, player, &trajectory, empty_board, should_stop, depth + 1);
          let cur_score = cur_score.min(trajectory.score());

          if cur_score > max_score {
            max_score = cur_score;
            best_move = NonZeroPos::new(our_pos);
            capture_depth = cur_capture_depth;
          }
          if cur_depth > max_depth {
            max_depth = cur_depth;
          }
        }

        for pos in marks {
          empty_board[pos] = 0;
        }

        field.undo();
        field.undo();
      }

      (best_move, max_score, max_depth, capture_depth)
    }
    _ => unreachable!("Trajectory with {} points", trajectory.len()),
  }
}

pub fn ladders(
  field: &mut Field,
  player: Player,
  depth_limit: u32,
  should_stop: &AtomicBool,
) -> (Option<NonZeroPos>, i32, Vec<Trajectory>) {
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();

  let trajectories = build_trajectories(field, player, 2, &mut empty_board, &should_stop);

  let base_score = field.score(player);
  let mut max_score = base_score;
  let mut best_move = None;
  let mut banned_trajectories = Vec::new();

  for trajectory in trajectories {
    if should_stop.load(Ordering::Relaxed) {
      break;
    }

    if trajectory.len() < 2 || !is_trajectoty_viable(field, &trajectory, player) {
      continue;
    }

    let marks = if let [pos1, _] = *trajectory.points().as_slice() {
      if trajectory.score() <= max_score {
        continue;
      }

      if let Some(&pos) = field
        .directions_diag(pos1)
        .iter()
        .find(|&&pos| field.cell(pos).is_players_point(player))
      {
        // mark one of near groups to not search trajectories from it
        mark_group(field, pos, player, &mut empty_board)
      } else {
        Vec::new()
      }
    } else {
      Vec::new()
    };

    let (cur_pos, cur_score, cur_max_depth, cur_capture_depth) =
      ladders_rec(field, player, &trajectory, &mut empty_board, should_stop, 0);
    let cur_score = cur_score.min(trajectory.score());
    if cur_score > max_score && cur_capture_depth > depth_limit {
      max_score = cur_score;
      best_move = cur_pos;
    } else if cur_score == base_score && cur_max_depth > depth_limit {
      banned_trajectories.push(trajectory);
    }

    for pos in marks {
      empty_board[pos] = 0;
    }
  }

  (best_move, max_score, banned_trajectories)
}
<commit_msg>Reduce complexity of liveness check.<commit_after>use oppai_common::common::is_last_move_stupid;
use oppai_common::trajectory::{build_trajectories, build_trajectories_from, Trajectory};
use oppai_field::field::wave_diag;
use oppai_field::field::{Field, NonZeroPos, Pos};
use oppai_field::player::Player;
use std::iter;
use std::sync::atomic::{AtomicBool, Ordering};

fn mark_group(field: &Field, start_pos: Pos, player: Player, empty_board: &mut Vec<u32>) -> Vec<Pos> {
  let mut marks = Vec::new();
  wave_diag(field.width(), start_pos, |pos| {
    if empty_board[pos] != 0 {
      return false;
    }
    let cell = field.cell(pos);
    if cell.is_players_point(player) {
      empty_board[pos] = 1;
      marks.push(pos);
      true
    } else {
      false
    }
  });
  marks
}

fn collect_near_moves(field: &Field, player: Player, empty_board: &mut Vec<u32>) -> Vec<Pos> {
  let mut moves = Vec::new();
  for &pos in field.points_seq().iter().filter(|&&pos| field.cell(pos).is_players_point(player)) {
    for &near_pos in field.directions(pos).iter() {
      if empty_board[near_pos] == 0 {
        moves.push(near_pos);
        empty_board[near_pos] = 1;
      }
    }
  }
  for &pos in &moves {
    empty_board[pos] = 0;
  }
  moves
}

fn is_trajectoty_alive(field: &mut Field, trajectory: &Trajectory, player: Player, empty_board: &mut Vec<u32>) -> bool {
  if trajectory.points().iter().any(|&pos| !field.is_putting_allowed(pos)) {
    return false;
  }

  for &pos in trajectory.points() {
    field.put_point(pos, player);
  }

  let result = field.get_delta_score(player) > 0 || {
    let enemy = player.next();
    let moves = collect_near_moves(field, enemy, empty_board);
    moves.into_iter().any(|pos| {
      field.is_putting_allowed(pos) && {
        field.put_point(pos, player);
        let result = field.get_delta_score(player) > 0
          && trajectory
            .points()
            .iter()
            .all(|&trajectory_pos| field.cell(trajectory_pos).is_bound());
        field.undo();
        result && {
          let enemies_around = field
            .directions(pos)
            .iter()
            .filter(|&&pos| field.cell(pos).is_players_point(enemy))
            .count();
          enemies_around < 3
            || enemies_around == 3
              && field
                .directions(pos)
                .iter()
                .all(|&near_pos| !field.cell(near_pos).is_putting_allowed())
        }
      }
    })
  };

  for _ in 0..trajectory.len() {
    field.undo();
  }

  result
}

fn is_trajectoty_viable(field: &mut Field, trajectory: &Trajectory, player: Player, empty_board: &mut Vec<u32>) -> bool {
  let moves = collect_near_moves(field, player, empty_board);
  let enemy = player.next();
  moves.into_iter().all(|enemy_pos| {
    !field.is_putting_allowed(enemy_pos) || {
      field.put_point(enemy_pos, enemy);

      if field.get_delta_score(enemy) == 0 {
        field.undo();
        return true;
      }

      let result = is_trajectoty_alive(field, trajectory, player, empty_board);

      field.undo();

      result
    }
  })
}

fn ladders_rec(
  field: &mut Field,
  player: Player,
  trajectory: &Trajectory,
  empty_board: &mut Vec<u32>,
  should_stop: &AtomicBool,
  depth: u32,
) -> (Option<NonZeroPos>, i32, u32, u32) {
  match *trajectory.points().as_slice() {
    [pos] => {
      field.put_point(pos, player);
      let cur_score = field.score(player);
      field.undo();
      (NonZeroPos::new(pos), cur_score, depth, depth)
    }
    [pos1, pos2] => {
      let mut max_score = field.score(player);
      let mut best_move = None;
      let mut max_depth = depth;
      let mut capture_depth = 0;

      for &(our_pos, enemy_pos) in &[(pos1, pos2), (pos2, pos1)] {
        if trajectory.score() <= max_score {
          break;
        }

        if field.cell(our_pos).is_players_empty_base(player.next()) {
          continue;
        }

        if !field.put_point(our_pos, player) {
          panic!(
            "Failed to put a point to ({}, {}) on the field:\n{}",
            field.to_x(our_pos),
            field.to_y(our_pos),
            field,
          );
        }

        if is_last_move_stupid(field, our_pos, player) {
          field.undo();
          continue;
        }

        if field.get_delta_score(player) > 0 {
          let cur_score = field.score(player);
          field.undo();
          if cur_score > max_score {
            max_score = cur_score;
            best_move = NonZeroPos::new(our_pos);
            capture_depth = depth;
          }
          continue;
        }

        if !field.put_point(enemy_pos, player.next()) {
          panic!(
            "Failed to put a point to ({}, {}) on the field:\n{}",
            field.to_x(our_pos),
            field.to_y(our_pos),
            field,
          );
        }

        let trajectories = build_trajectories_from(field, our_pos, player, 2, empty_board, should_stop);

        if should_stop.load(Ordering::Relaxed) {
          break;
        }

        let marks = mark_group(field, our_pos, player, empty_board);

        for trajectory in trajectories {
          if trajectory.score() <= max_score {
            continue;
          }

          let (_, cur_score, cur_depth, cur_capture_depth) =
            ladders_rec(field, player, &trajectory, empty_board, should_stop, depth + 1);
          let cur_score = cur_score.min(trajectory.score());

          if cur_score > max_score {
            max_score = cur_score;
            best_move = NonZeroPos::new(our_pos);
            capture_depth = cur_capture_depth;
          }
          if cur_depth > max_depth {
            max_depth = cur_depth;
          }
        }

        for pos in marks {
          empty_board[pos] = 0;
        }

        field.undo();
        field.undo();
      }

      (best_move, max_score, max_depth, capture_depth)
    }
    _ => unreachable!("Trajectory with {} points", trajectory.len()),
  }
}

pub fn ladders(
  field: &mut Field,
  player: Player,
  depth_limit: u32,
  should_stop: &AtomicBool,
) -> (Option<NonZeroPos>, i32, Vec<Trajectory>) {
  let mut empty_board = iter::repeat(0u32).take(field.length()).collect();

  let trajectories = build_trajectories(field, player, 2, &mut empty_board, &should_stop);

  let base_score = field.score(player);
  let mut max_score = base_score;
  let mut best_move = None;
  let mut banned_trajectories = Vec::new();

  for trajectory in trajectories {
    if should_stop.load(Ordering::Relaxed) {
      break;
    }

    if trajectory.len() < 2 || !is_trajectoty_viable(field, &trajectory, player, &mut empty_board) {
      continue;
    }

    let marks = if let [pos1, _] = *trajectory.points().as_slice() {
      if trajectory.score() <= max_score {
        continue;
      }

      if let Some(&pos) = field
        .directions_diag(pos1)
        .iter()
        .find(|&&pos| field.cell(pos).is_players_point(player))
      {
        // mark one of near groups to not search trajectories from it
        mark_group(field, pos, player, &mut empty_board)
      } else {
        Vec::new()
      }
    } else {
      Vec::new()
    };

    let (cur_pos, cur_score, cur_max_depth, cur_capture_depth) =
      ladders_rec(field, player, &trajectory, &mut empty_board, should_stop, 0);
    let cur_score = cur_score.min(trajectory.score());
    if cur_score > max_score && cur_capture_depth > depth_limit {
      max_score = cur_score;
      best_move = cur_pos;
    } else if cur_score == base_score && cur_max_depth > depth_limit {
      banned_trajectories.push(trajectory);
    }

    for pos in marks {
      empty_board[pos] = 0;
    }
  }

  (best_move, max_score, banned_trajectories)
}
<|endoftext|>


<commit_before>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::marker::PhantomData;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example:: A => 3, Example:: B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        <EnumMap<_, _> as core::convert::From<_>>::from(|i: u8| i)
            .into_iter()
            .collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}
<commit_msg>Add clear test<commit_after>#[macro_use]
extern crate enum_map;

use enum_map::{Enum, EnumMap, IntoIter};

use std::cell::RefCell;
use std::collections::HashSet;
use std::marker::PhantomData;

trait From<T>: Sized {
    fn from(_: T) -> Self {
        unreachable!();
    }
}

impl<T, U> From<T> for U {}

#[derive(Copy, Clone, Debug, Enum, PartialEq)]
enum Example {
    A,
    B,
    C,
}

#[test]
fn test_bool() {
    let mut map = enum_map! { false => 24, true => 42 };
    assert_eq!(map[false], 24);
    assert_eq!(map[true], 42);
    map[false] += 1;
    assert_eq!(map[false], 25);
    for (key, item) in &mut map {
        if !key {
            *item += 1;
        }
    }
    assert_eq!(map[false], 26);
    assert_eq!(map[true], 42);
}

#[test]
fn test_clone() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(map.clone(), map);
}

#[test]
fn test_debug() {
    let map = enum_map! { false => 3, true => 5 };
    assert_eq!(format!("{:?}", map), "{false: 3, true: 5}");
}

#[test]
fn test_hash() {
    let map = enum_map! { false => 3, true => 5 };
    let mut set = HashSet::new();
    set.insert(map);
    assert!(set.contains(&map));
}

#[test]
fn test_clear() {
    let mut map = enum_map! { false => 1, true => 2 };
    map.clear();
    assert_eq!(map[true], 0);
    assert_eq!(map[false], 0);
}

#[test]
fn discriminants() {
    #[derive(Debug, Enum, PartialEq)]
    enum Discriminants {
        A = 2000,
        B = 3000,
        C = 1000,
    }
    let mut map = EnumMap::new();
    map[Discriminants::A] = 3;
    map[Discriminants::B] = 2;
    map[Discriminants::C] = 1;
    let mut pairs = map.iter();
    assert_eq!(pairs.next(), Some((Discriminants::A, &3)));
    assert_eq!(pairs.next(), Some((Discriminants::B, &2)));
    assert_eq!(pairs.next(), Some((Discriminants::C, &1)));
    assert_eq!(pairs.next(), None);
}

#[test]
fn extend() {
    let mut map = enum_map! { _ => 0 };
    map.extend(vec![(Example::A, 3)]);
    map.extend(vec![(&Example::B, &4)]);
    assert_eq!(
        map,
        enum_map! { Example:: A => 3, Example:: B => 4, Example::C => 0 }
    );
}

#[test]
fn huge_enum() {
    #[derive(Enum)]
    enum Example {
        A,
        B,
        C,
        D,
        E,
        F,
        G,
        H,
        I,
        J,
        K,
        L,
        M,
        N,
        O,
        P,
        Q,
        R,
        S,
        T,
        U,
        V,
        W,
        X,
        Y,
        Z,
        Aa,
        Bb,
        Cc,
        Dd,
        Ee,
        Ff,
        Gg,
        Hh,
        Ii,
        Jj,
        Kk,
        Ll,
        Mm,
        Nn,
        Oo,
        Pp,
        Qq,
        Rr,
        Ss,
        Tt,
        Uu,
        Vv,
        Ww,
        Xx,
        Yy,
        Zz,
    }

    let map = enum_map! { _ => 2 };
    assert_eq!(map[Example::Xx], 2);
}

#[test]
fn iterator_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter()
            .len(),
        3
    );
}

#[test]
fn iter_mut_len() {
    assert_eq!(
        enum_map! { Example::A | Example::B | Example::C => 0 }
            .iter_mut()
            .len(),
        3
    );
}

#[test]
fn into_iter_len() {
    assert_eq!(enum_map! { Example::A | _ => 0 }.into_iter().len(), 3);
}

#[test]
fn iterator_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter()
            .next_back(),
        Some((Example::C, &3))
    );
}

#[test]
fn iter_mut_next_back() {
    assert_eq!(
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .iter_mut()
            .next_back(),
        Some((Example::C, &mut 3))
    );
}

#[test]
fn into_iter() {
    let mut iter = enum_map! { true => 5, false => 7 }.into_iter();
    assert_eq!(iter.next(), Some((false, 7)));
    assert_eq!(iter.next(), Some((true, 5)));
    assert_eq!(iter.next(), None);
    assert_eq!(iter.next(), None);
}

#[test]
fn into_iter_u8() {
    assert_eq!(
        <EnumMap<_, _> as core::convert::From<_>>::from(|i: u8| i)
            .into_iter()
            .collect::<Vec<_>>(),
        (0..256).map(|x| (x as u8, x as u8)).collect::<Vec<_>>()
    );
}

struct DropReporter<'a> {
    into: &'a RefCell<Vec<usize>>,
    value: usize,
}

impl<'a> Drop for DropReporter<'a> {
    fn drop(&mut self) {
        self.into.borrow_mut().push(self.value);
    }
}

#[test]
fn into_iter_drop() {
    let dropped = RefCell::new(Vec::new());
    let mut a: IntoIter<Example, _> = enum_map! {
        k => DropReporter {
            into: &dropped,
            value: k as usize,
        },
    }
    .into_iter();
    assert_eq!(a.next().unwrap().0, Example::A);
    assert_eq!(*dropped.borrow(), &[0]);
    drop(a);
    assert_eq!(*dropped.borrow(), &[0, 1, 2]);
}

#[test]
fn values_rev_collect() {
    assert_eq!(
        vec![3, 2, 1],
        enum_map! { Example::A => 1, Example::B => 2, Example::C => 3 }
            .values()
            .rev()
            .cloned()
            .collect::<Vec<_>>()
    );
}

#[test]
fn values_len() {
    assert_eq!(enum_map! { false => 0, true => 1 }.values().len(), 2);
}

#[test]
fn values_mut_next_back() {
    let mut map = enum_map! { false => 0, true => 1 };
    assert_eq!(map.values_mut().next_back(), Some(&mut 1));
}
#[test]
fn test_u8() {
    let mut map = enum_map! { b'a' => 4, _ => 0 };
    map[b'c'] = 3;
    assert_eq!(map[b'a'], 4);
    assert_eq!(map[b'b'], 0);
    assert_eq!(map[b'c'], 3);
    assert_eq!(map.iter().next(), Some((0, &0)));
}

#[derive(Enum)]
enum Void {}

#[test]
fn empty_map() {
    let void: EnumMap<Void, Void> = enum_map! {};
    assert!(void.is_empty());
}

#[test]
#[should_panic]
fn empty_value() {
    let _void: EnumMap<bool, Void> = enum_map! { _ => unreachable!() };
}

#[derive(Clone, Copy)]
enum X {
    A(PhantomData<*const ()>),
}

impl<V> Enum<V> for X {
    type Array = [V; 1];
    const POSSIBLE_VALUES: usize = 1;

    fn slice(array: &[V; 1]) -> &[V] {
        array
    }

    fn slice_mut(array: &mut [V; 1]) -> &mut [V] {
        array
    }

    fn from_usize(arg: usize) -> X {
        assert_eq!(arg, 0);
        X::A(PhantomData)
    }

    fn to_usize(self) -> usize {
        0
    }

    fn from_function<F: FnMut(Self) -> V>(mut f: F) -> [V; 1] {
        [f(X::A(PhantomData))]
    }
}

fn assert_sync_send<T: Sync + Send>(_: T) {}

#[test]
fn assert_enum_map_does_not_copy_sync_send_dependency_of_keys() {
    let mut map = enum_map! { X::A(PhantomData) => true };
    assert_sync_send(map);
    assert_sync_send(&map);
    assert_sync_send(&mut map);
    assert_sync_send(map.iter());
    assert_sync_send(map.iter_mut());
    assert_sync_send(map.into_iter());
    assert_eq!(map[X::A(PhantomData)], true);
}

#[test]
fn test_sum() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter()
            .map(|(_, v)| v)
            .sum::<u32>(),
        32_640
    );
}

#[test]
fn test_sum_mut() {
    assert_eq!(
        enum_map! { i => u8::into(i) }
            .iter_mut()
            .map(|(_, &mut v)| -> u32 { v })
            .sum::<u32>(),
        32_640
    );
}
<|endoftext|>


<commit_before>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<commit_msg>Auto merge of #993 - redox-os:master, r=alexcrichton<commit_after>pub type c_char = i8;
pub type c_long = i64;
pub type c_ulong = u64;

pub type wchar_t = i16;

pub type off_t = c_long;
pub type mode_t = u16;
pub type time_t = i64;
pub type pid_t = usize;
pub type gid_t = usize;
pub type uid_t = usize;

pub type suseconds_t = i64;

s! {
    pub struct timeval {
        pub tv_sec: time_t,
        pub tv_usec: suseconds_t,
    }

    pub struct timespec {
        pub tv_sec: time_t,
        pub tv_nsec: c_long,
    }
}

pub const STDIN_FILENO: ::c_int = 0;
pub const STDOUT_FILENO: ::c_int = 1;
pub const STDERR_FILENO: ::c_int = 2;

pub const EXIT_FAILURE: ::c_int = 1;
pub const EXIT_SUCCESS: ::c_int = 0;

pub const S_ISUID: ::c_int = 0x800;
pub const S_ISGID: ::c_int = 0x400;
pub const S_ISVTX: ::c_int = 0x200;

pub const S_IFIFO: mode_t = 0x1000;
pub const S_IFCHR: mode_t = 0x2000;
pub const S_IFBLK: mode_t = 0x6000;
pub const S_IFDIR: mode_t = 0x4000;
pub const S_IFREG: mode_t = 0x8000;
pub const S_IFLNK: mode_t = 0xA000;
pub const S_IFSOCK: mode_t = 0xC000;
pub const S_IFMT: mode_t = 0xF000;
pub const S_IEXEC: mode_t = 0x40;
pub const S_IWRITE: mode_t = 0x80;
pub const S_IREAD: mode_t = 0x100;
pub const S_IRWXU: mode_t = 0x1C0;
pub const S_IXUSR: mode_t = 0x40;
pub const S_IWUSR: mode_t = 0x80;
pub const S_IRUSR: mode_t = 0x100;
pub const S_IRWXG: mode_t = 0x38;
pub const S_IXGRP: mode_t = 0x8;
pub const S_IWGRP: mode_t = 0x10;
pub const S_IRGRP: mode_t = 0x20;
pub const S_IRWXO: mode_t = 0x7;
pub const S_IXOTH: mode_t = 0x1;
pub const S_IWOTH: mode_t = 0x2;
pub const S_IROTH: mode_t = 0x4;

pub const F_DUPFD: ::c_int = 0;
pub const F_GETFD: ::c_int = 1;
pub const F_SETFD: ::c_int = 2;
pub const F_GETFL: ::c_int = 3;
pub const F_SETFL: ::c_int = 4;

pub const O_RDONLY: ::c_int =     0x0001_0000;
pub const O_WRONLY: ::c_int =     0x0002_0000;
pub const O_RDWR: ::c_int =       0x0003_0000;
pub const O_NONBLOCK: ::c_int =   0x0004_0000;
pub const O_APPEND: ::c_int =     0x0008_0000;
pub const O_SHLOCK: ::c_int =     0x0010_0000;
pub const O_EXLOCK: ::c_int =     0x0020_0000;
pub const O_ASYNC: ::c_int =      0x0040_0000;
pub const O_FSYNC: ::c_int =      0x0080_0000;
pub const O_CLOEXEC: ::c_int =    0x0100_0000;
pub const O_CREAT: ::c_int =      0x0200_0000;
pub const O_TRUNC: ::c_int =      0x0400_0000;
pub const O_EXCL: ::c_int =       0x0800_0000;
pub const O_DIRECTORY: ::c_int =  0x1000_0000;
pub const O_STAT: ::c_int =       0x2000_0000;
pub const O_SYMLINK: ::c_int =    0x4000_0000;
pub const O_NOFOLLOW: ::c_int =   0x8000_0000;
pub const O_ACCMODE: ::c_int =    O_RDONLY | O_WRONLY | O_RDWR;

pub const SIGHUP:    ::c_int = 1;
pub const SIGINT:    ::c_int = 2;
pub const SIGQUIT:   ::c_int = 3;
pub const SIGILL:    ::c_int = 4;
pub const SIGTRAP:   ::c_int = 5;
pub const SIGABRT:   ::c_int = 6;
pub const SIGBUS:    ::c_int = 7;
pub const SIGFPE:    ::c_int = 8;
pub const SIGKILL:   ::c_int = 9;
pub const SIGUSR1:   ::c_int = 10;
pub const SIGSEGV:   ::c_int = 11;
pub const SIGUSR2:   ::c_int = 12;
pub const SIGPIPE:   ::c_int = 13;
pub const SIGALRM:   ::c_int = 14;
pub const SIGTERM:   ::c_int = 15;
pub const SIGSTKFLT: ::c_int = 16;
pub const SIGCHLD:   ::c_int = 17;
pub const SIGCONT:   ::c_int = 18;
pub const SIGSTOP:   ::c_int = 19;
pub const SIGTSTP:   ::c_int = 20;
pub const SIGTTIN:   ::c_int = 21;
pub const SIGTTOU:   ::c_int = 22;
pub const SIGURG:    ::c_int = 23;
pub const SIGXCPU:   ::c_int = 24;
pub const SIGXFSZ:   ::c_int = 25;
pub const SIGVTALRM: ::c_int = 26;
pub const SIGPROF:   ::c_int = 27;
pub const SIGWINCH:  ::c_int = 28;
pub const SIGIO:     ::c_int = 29;
pub const SIGPWR:    ::c_int = 30;
pub const SIGSYS:    ::c_int = 31;

extern {
    pub fn memalign(align: ::size_t, size: ::size_t) -> *mut ::c_void;
    pub fn read(fd: ::c_int, buf: *mut ::c_void, count: ::size_t)
                -> ::ssize_t;
    pub fn write(fd: ::c_int, buf: *const ::c_void, count: ::size_t)
                 -> ::ssize_t;
    pub fn fcntl(fd: ::c_int, cmd: ::c_int, ...) -> ::c_int;
    pub fn close(fd: ::c_int) -> ::c_int;
}

#[link(name = "c")]
#[link(name = "m")]
extern {}

pub use self::net::*;

mod net;
<|endoftext|>