<commit_before>extern crate byteorder;
extern crate tiny_keccak;

use disk_file::{CHUNK_SIZE, HASH_SIZE};
use disk_file::DiskFile;
use self::byteorder::{BigEndian, ByteOrder};
use self::tiny_keccak::Keccak;
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::PathBuf;

const MAGIC_NUMBER: u32 = 1400136018;
const PROTOCOL_VERSION: u16 = 0;
const ACTION_SEND_DESCRIPTION: u8 = 0;

pub struct Pool
{
    data: Vec<DiskFile>,
    file_index_map: HashMap<u8, usize>,
    update_left: HashSet<(u8, u32)>,
    read_only: bool,
    map_hash_write: HashMap<[u8; HASH_SIZE], Vec<(u8, u32)>>,
    map_hash_read: HashMap<[u8; HASH_SIZE], (u8, u32)>,
    cache_set_sizes: Vec<u64>,
    cache_file_path: Vec<PathBuf>,
}

pub struct FileDescription
{
    pub id: u8,
    pub name: String,
    pub name_hash: [u8; HASH_SIZE],
    pub hash: [u8; HASH_SIZE],
    pub chunk: Vec<[u8; HASH_SIZE]>,
    pub last_chunk_size: u16,
}

impl Pool
{
    pub fn new(files: &Vec<PathBuf>, first_packet: Option<Vec<u8>>) -> Pool
    {
        let have_sizes: bool = first_packet.is_some();
        let mut p = Pool {
            data: Vec::new(),
            read_only: !have_sizes,
            file_index_map: HashMap::new(),
            update_left: HashSet::new(),
            map_hash_write: HashMap::new(),
            map_hash_read: HashMap::new(),
            cache_set_sizes: Vec::new(),
            cache_file_path: files.clone(),
        };
        if have_sizes
        {
            p.update_tables(&first_packet.unwrap());
        }
        {
            let sizes = &p.cache_set_sizes;
            if have_sizes && sizes.len() != files.len()
            {
                panic!("Files and sizes mismatch!");
            }
            if files.len() > 255
            {
                panic!("stardust can only handle up to 255 files");
            }
            for i in 0..files.len()
            {
                let tmp_size = if have_sizes
                {
                    Some(sizes[i])
                }
                else
                {
                    None
                };
                p.data.push(DiskFile::new(&files[i], tmp_size));
            }
        }
        for i in 0..p.data.len()
        {
            for j in 0..p.data[i].get_num_chunks()
            {
                let tmp_chunk_hash = p.data[i].get_chunk_hash(j);
                if p.map_hash_read.contains_key(&tmp_chunk_hash)
                {
                    let &(tmp_file_id, tmp_chunk_id) = p.map_hash_read.get(&tmp_chunk_hash).unwrap();
                    if p.data[i].read_chunk(j) != p.data[tmp_file_id as usize].read_chunk(tmp_chunk_id as usize)
                    {
                        panic!("FATAL: Hash collision!");
                    }
                }
                else
                {
                    p.map_hash_read.insert(tmp_chunk_hash, (i as u8, j as u32));
                }
            }
        }
        return p;
    }

    fn get_description(&self) -> Vec<FileDescription>
    {
        let mut v: Vec<FileDescription> = Vec::new();
        for i in 0..self.data.len()
        {
            v.push(FileDescription::new(&self.data[i], i as u8));
        }
        return v;
    }

    pub fn generate_binary_description(&self) -> Vec<Vec<u8>>
    {
        let description = self.get_description();
        let mut bin_data: Vec<Vec<u8>> = Vec::new();
        let mut file_index: usize = 0;
        let mut chunk_index: usize = 0;
        while file_index < description.len()
        {
            let mut v: Vec<u8> = Vec::new();
            let mut buffer: [u8; 128] = [0; 128];
            // Magic number
            BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
            v.extend_from_slice(&buffer[0..4]);
            // Protocol version
            BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
            v.extend_from_slice(&buffer[0..2]);
            // Action
            v.push(ACTION_SEND_DESCRIPTION);
            // Number of files
            v.push(description.len() as u8);
            // Files description
            for desc in &description
            {
                v.push(desc.id);
                v.extend_from_slice(&desc.name_hash);
                v.extend_from_slice(&desc.hash);
                BigEndian::write_u32(&mut buffer[0..4], desc.chunk.len() as u32);
                v.extend_from_slice(&buffer[0..4]);
                BigEndian::write_u16(&mut buffer[0..2], desc.last_chunk_size);
                v.extend_from_slice(&buffer[0..2]);
            }
            // Chunks information
            'outer: while file_index < description.len()
            {
                while chunk_index < description[file_index].chunk.len()
                {
                    if v.len() >= 60000
                    {
                        break 'outer;
                    }
                    v.push(description[file_index].id as u8);
                    v.extend_from_slice(&description[file_index].chunk[chunk_index]);
                    BigEndian::write_u32(&mut buffer[0..4], chunk_index as u32);
                    v.extend_from_slice(&buffer[0..4]);
                    chunk_index += 1;
                }
                chunk_index = 0;
                file_index += 1;
            }
            bin_data.push(v);
        }
        return bin_data;
    }

    fn unwrap_description(&self, data: &Vec<u8>, i: usize) -> (u8, [u8; HASH_SIZE], [u8; HASH_SIZE], u32, u16)
    {
        let struct_size: usize = 7 + 2 * HASH_SIZE;
        let file_id: u8 = data[i * struct_size + 1];
        let mut name_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
        name_hash.copy_from_slice(&data[(i * struct_size + 2)..(i * struct_size + 2 + HASH_SIZE)]);
        let mut file_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
        file_hash.copy_from_slice(&data[(i * struct_size + 2 + HASH_SIZE)..(i * struct_size + 2 + 2 * HASH_SIZE)]);
        let num_chunks: u32 = BigEndian::read_u32(&data[(i * struct_size + 2 + 2 * HASH_SIZE)..(i * struct_size + 6 +
                                                                                2 * HASH_SIZE)]);
        let last_chunk_size: u16 = BigEndian::read_u16(&data[(i * struct_size + 6 + 2 * HASH_SIZE)..(i * struct_size + 8 +
                                                                                2 * HASH_SIZE)]);
        return (file_id, name_hash, file_hash, num_chunks, last_chunk_size);
    }

    pub fn update_tables(&mut self, data: &Vec<u8>) -> bool
    {
        if self.read_only
        {
            panic!("Writing on read-only table!");
        }
        if self.cache_set_sizes.len() == 0
        {
            self.cache_set_sizes = vec![0, self.cache_file_path.len() as u64];
            let num_files: usize = data[0] as usize;
            for i in 0..num_files
            {
                let (_, name_hash, _, num_chunks, mut last_chunk_size) = self.unwrap_description(data, i);
                last_chunk_size = last_chunk_size % CHUNK_SIZE as u16;
                let file_size = num_chunks as u64 * CHUNK_SIZE as u64 + last_chunk_size as u64;
                for j in 0..self.cache_file_path.len()
                {
                    let mut name_sha3 = Keccak::new_sha3_256();
                    let req_file_name = String::from(self.cache_file_path[j].file_name().unwrap().to_str().unwrap_or(""));
                    if req_file_name == ""
                    {
                        panic!("Error while decoding filename");
                    }
                    let mut req_file_name_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
                    name_sha3.update(req_file_name.as_bytes());
                    name_sha3.finalize(&mut req_file_name_hash);
                    if req_file_name_hash == name_hash
                    {
                        self.cache_set_sizes[j] = file_size;
                        break;
                    }
                }
            }
            for i in 0..self.cache_set_sizes.len()
            {
                if self.cache_set_sizes[i] == 0
                {
                    panic!("The server doesn't have all requested files!");
                }
            }
            return false;
        }
        if self.file_index_map.len() == 0
        {
            let num_files: usize = data[0] as usize;
            for i in 0..num_files
            {
                let (file_id, name_hash, _, _, _) = self.unwrap_description(data, i);
                for j in 0..self.data.len()
                {
                    if name_hash == self.data[j].get_name_hash()
                    {
                        self.file_index_map.insert(file_id, j);
                        for k in 0..self.data[j].get_num_chunks()
                        {
                            self.update_left.insert((file_id, k as u32));
                        }
                        break;
                    }
                }
            }
        }
        let struct_size: usize = 7 + 2 * HASH_SIZE;
        let first_index: usize = struct_size * data[0] as usize + 1;
        let desc_size: usize = 5 + HASH_SIZE;
        let num_desc = (data.len() - first_index) / desc_size;
        if (data.len() - first_index) % desc_size != 0
        {
            panic!("Received a corrupted packet");
        }
        for i in 0..num_desc
        {
            let local_slice = &data[(first_index + i * desc_size)..(first_index + (i + 1) * desc_size)];
            let fid: u8 = local_slice[0];
            let mut chunk_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
            chunk_hash.clone_from_slice(&local_slice[1..(HASH_SIZE + 1)]);
            let chunk_id: u32 = BigEndian::read_u32(&local_slice[(HASH_SIZE + 1)..(HASH_SIZE + 5)]);
            if self.update_left.contains(&(fid, chunk_id))
            {
                if !self.map_hash_write.contains_key(&chunk_hash)
                {
                    let mut chunk_hash2: [u8; HASH_SIZE] = [0; HASH_SIZE];
                    chunk_hash2.clone_from_slice(&chunk_hash);
                    self.map_hash_write.insert(chunk_hash2, Vec::new());
                }
                self.map_hash_write.get_mut(&chunk_hash).unwrap().push((fid, chunk_id));
                self.update_left.remove(&(fid, chunk_id));
            }
        }
        return self.update_left.is_empty();
    }

    pub fn process_chunk(&mut self, chunk_hash: [u8; HASH_SIZE], chunk: &Vec<u8>)
    {
        if self.read_only
        {
            panic!("Writing on read-only files!");
        }
        if !self.map_hash_write.contains_key(&chunk_hash)
        {
            return;
        }
        {
            let vec_mapped = self.map_hash_write.get(&chunk_hash).unwrap();
            for i in vec_mapped
            {
                let &(unmapped_fid, chunk_id) = i;
                if !self.file_index_map.contains_key(&unmapped_fid)
                {
                    continue;
                }
                let mapped_fid = self.file_index_map.get(&unmapped_fid).unwrap().clone();
                self.data[mapped_fid].write_chunk(chunk_id as usize, chunk);
            }
        }
        self.map_hash_write.remove(&chunk_hash);

    }

    pub fn get_chunk(&mut self, chunk_hash: [u8; HASH_SIZE]) -> Option<Vec<u8>>
    {
        if !self.map_hash_read.contains_key(&chunk_hash)
        {
            return None;
        }
        let &(i, j) = self.map_hash_read.get(&chunk_hash).unwrap();
        return Some(self.data[i as usize].read_chunk(j as usize));
    }
}

impl FileDescription
{
    pub fn new(diskfile: &DiskFile, _id: u8) -> FileDescription
    {
        let mut fd = FileDescription {
            id: _id,
            name: diskfile.get_file_name(),
            name_hash: diskfile.get_name_hash(),
            hash: diskfile.get_file_hash(),
            chunk: Vec::new(),
            last_chunk_size: diskfile.get_chunk_size(diskfile.get_num_chunks() - 1) as u16,
        };
        for i in 0..diskfile.get_num_chunks()
        {
            fd.chunk.push(diskfile.get_chunk_hash(i));
        }
        return fd;
    }
}
<commit_msg>Implemented serialization<commit_after>extern crate byteorder;
extern crate tiny_keccak;
extern crate lz4_compress as lz4;

use disk_file::{CHUNK_SIZE, HASH_SIZE};
use disk_file::DiskFile;
use self::byteorder::{BigEndian, ByteOrder};
use self::tiny_keccak::Keccak;
use std::collections::HashMap;
use std::collections::HashSet;
use std::path::PathBuf;

const MAGIC_NUMBER: u32 = 1400136018;
const PROTOCOL_VERSION: u16 = 0;
const ACTION_SEND_DESCRIPTION: u8 = 0;
const ACTION_SEND_DATA: u8 = 1;
const ACTION_SEND_CHUNK_REQUEST: u8 = 2;

pub struct Pool
{
    data: Vec<DiskFile>,
    file_index_map: HashMap<u8, usize>,
    update_left: HashSet<(u8, u32)>,
    read_only: bool,
    map_hash_write: HashMap<[u8; HASH_SIZE], Vec<(u8, u32)>>,
    map_hash_read: HashMap<[u8; HASH_SIZE], (u8, u32)>,
    cache_set_sizes: Vec<u64>,
    cache_file_path: Vec<PathBuf>,
}

pub struct FileDescription
{
    pub id: u8,
    pub name: String,
    pub name_hash: [u8; HASH_SIZE],
    pub hash: [u8; HASH_SIZE],
    pub chunk: Vec<[u8; HASH_SIZE]>,
    pub last_chunk_size: u16,
}

// Proxy functions:
// get_binary_data
// generate_binary_description
// process_binary_data
// process_binary_description
// get_binary_chunk_request TODO
// process_binary_chunk_request TODO
// get_binary_send_packet TODO

impl Pool
{
    pub fn new(files: &Vec<PathBuf>, first_packet: Option<Vec<u8>>) -> Pool
    {
        let have_sizes: bool = first_packet.is_some();
        let mut p = Pool {
            data: Vec::new(),
            read_only: !have_sizes,
            file_index_map: HashMap::new(),
            update_left: HashSet::new(),
            map_hash_write: HashMap::new(),
            map_hash_read: HashMap::new(),
            cache_set_sizes: Vec::new(),
            cache_file_path: files.clone(),
        };
        if have_sizes
        {
            p.process_binary_description(&first_packet.unwrap());
        }
        {
            let sizes = &p.cache_set_sizes;
            if have_sizes && sizes.len() != files.len()
            {
                panic!("Files and sizes mismatch!");
            }
            if files.len() > 255
            {
                panic!("stardust can only handle up to 255 files");
            }
            for i in 0..files.len()
            {
                let tmp_size = if have_sizes
                {
                    Some(sizes[i])
                }
                else
                {
                    None
                };
                p.data.push(DiskFile::new(&files[i], tmp_size));
            }
        }
        for i in 0..p.data.len()
        {
            for j in 0..p.data[i].get_num_chunks()
            {
                let tmp_chunk_hash = p.data[i].get_chunk_hash(j);
                if p.map_hash_read.contains_key(&tmp_chunk_hash)
                {
                    let &(tmp_file_id, tmp_chunk_id) = p.map_hash_read.get(&tmp_chunk_hash).unwrap();
                    if p.data[i].read_chunk(j) != p.data[tmp_file_id as usize].read_chunk(tmp_chunk_id as usize)
                    {
                        panic!("FATAL: Hash collision!");
                    }
                }
                else
                {
                    p.map_hash_read.insert(tmp_chunk_hash, (i as u8, j as u32));
                }
            }
        }
        return p;
    }

    fn get_description(&self) -> Vec<FileDescription>
    {
        let mut v: Vec<FileDescription> = Vec::new();
        for i in 0..self.data.len()
        {
            v.push(FileDescription::new(&self.data[i], i as u8));
        }
        return v;
    }

    pub fn generate_binary_description(&self) -> Vec<Vec<u8>>
    {
        let description = self.get_description();
        let mut bin_data: Vec<Vec<u8>> = Vec::new();
        let mut file_index: usize = 0;
        let mut chunk_index: usize = 0;
        while file_index < description.len()
        {
            let mut v: Vec<u8> = Vec::new();
            let mut buffer: [u8; 128] = [0; 128];
            // Magic number
            BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
            v.extend_from_slice(&buffer[0..4]);
            // Protocol version
            BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
            v.extend_from_slice(&buffer[0..2]);
            // Action
            v.push(ACTION_SEND_DESCRIPTION);
            // Number of files
            v.push(description.len() as u8);
            // Files description
            for desc in &description
            {
                v.push(desc.id);
                v.extend_from_slice(&desc.name_hash);
                v.extend_from_slice(&desc.hash);
                BigEndian::write_u32(&mut buffer[0..4], desc.chunk.len() as u32);
                v.extend_from_slice(&buffer[0..4]);
                BigEndian::write_u16(&mut buffer[0..2], desc.last_chunk_size);
                v.extend_from_slice(&buffer[0..2]);
            }
            // Chunks information
            'outer: while file_index < description.len()
            {
                while chunk_index < description[file_index].chunk.len()
                {
                    if v.len() >= 60000
                    {
                        break 'outer;
                    }
                    v.push(description[file_index].id as u8);
                    v.extend_from_slice(&description[file_index].chunk[chunk_index]);
                    BigEndian::write_u32(&mut buffer[0..4], chunk_index as u32);
                    v.extend_from_slice(&buffer[0..4]);
                    chunk_index += 1;
                }
                chunk_index = 0;
                file_index += 1;
            }
            bin_data.push(v);
        }
        return bin_data;
    }

    fn unwrap_description(&self, data: &Vec<u8>, i: usize) -> (u8, [u8; HASH_SIZE], [u8; HASH_SIZE], u32, u16)
    {
        let struct_size: usize = 7 + 2 * HASH_SIZE;
        let file_id: u8 = data[i * struct_size + 1];
        let mut name_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
        name_hash.copy_from_slice(&data[(i * struct_size + 2)..(i * struct_size + 2 + HASH_SIZE)]);
        let mut file_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
        file_hash.copy_from_slice(&data[(i * struct_size + 2 + HASH_SIZE)..(i * struct_size + 2 + 2 * HASH_SIZE)]);
        let num_chunks: u32 = BigEndian::read_u32(&data[(i * struct_size + 2 + 2 * HASH_SIZE)..(i * struct_size + 6 +
                                                                                2 * HASH_SIZE)]);
        let last_chunk_size: u16 = BigEndian::read_u16(&data[(i * struct_size + 6 + 2 * HASH_SIZE)..(i * struct_size + 8 +
                                                                                2 * HASH_SIZE)]);
        return (file_id, name_hash, file_hash, num_chunks, last_chunk_size);
    }

    pub fn process_binary_description(&mut self, data: &Vec<u8>) -> bool
    {
        if self.read_only
        {
            panic!("Writing on read-only table!");
        }
        if self.cache_set_sizes.len() == 0
        {
            self.cache_set_sizes = vec![0, self.cache_file_path.len() as u64];
            let num_files: usize = data[0] as usize;
            for i in 0..num_files
            {
                let (_, name_hash, _, num_chunks, mut last_chunk_size) = self.unwrap_description(data, i);
                last_chunk_size = last_chunk_size % CHUNK_SIZE as u16;
                let file_size = num_chunks as u64 * CHUNK_SIZE as u64 + last_chunk_size as u64;
                for j in 0..self.cache_file_path.len()
                {
                    let mut name_sha3 = Keccak::new_sha3_256();
                    let req_file_name = String::from(self.cache_file_path[j].file_name().unwrap().to_str().unwrap_or(""));
                    if req_file_name == ""
                    {
                        panic!("Error while decoding filename");
                    }
                    let mut req_file_name_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
                    name_sha3.update(req_file_name.as_bytes());
                    name_sha3.finalize(&mut req_file_name_hash);
                    if req_file_name_hash == name_hash
                    {
                        self.cache_set_sizes[j] = file_size;
                        break;
                    }
                }
            }
            for i in 0..self.cache_set_sizes.len()
            {
                if self.cache_set_sizes[i] == 0
                {
                    panic!("The server doesn't have all requested files!");
                }
            }
            return false;
        }
        if self.file_index_map.len() == 0
        {
            let num_files: usize = data[0] as usize;
            for i in 0..num_files
            {
                let (file_id, name_hash, _, _, _) = self.unwrap_description(data, i);
                for j in 0..self.data.len()
                {
                    if name_hash == self.data[j].get_name_hash()
                    {
                        self.file_index_map.insert(file_id, j);
                        for k in 0..self.data[j].get_num_chunks()
                        {
                            self.update_left.insert((file_id, k as u32));
                        }
                        break;
                    }
                }
            }
        }
        let struct_size: usize = 7 + 2 * HASH_SIZE;
        let first_index: usize = struct_size * data[0] as usize + 1;
        let desc_size: usize = 5 + HASH_SIZE;
        let num_desc = (data.len() - first_index) / desc_size;
        if (data.len() - first_index) % desc_size != 0
        {
            panic!("Received a corrupted packet");
        }
        for i in 0..num_desc
        {
            let local_slice = &data[(first_index + i * desc_size)..(first_index + (i + 1) * desc_size)];
            let fid: u8 = local_slice[0];
            let mut chunk_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
            chunk_hash.clone_from_slice(&local_slice[1..(HASH_SIZE + 1)]);
            let chunk_id: u32 = BigEndian::read_u32(&local_slice[(HASH_SIZE + 1)..(HASH_SIZE + 5)]);
            if self.update_left.contains(&(fid, chunk_id))
            {
                let mapped_fid: usize = self.file_index_map.get(&fid).unwrap().clone();
                if self.data[mapped_fid].get_chunk_hash(chunk_id as usize) != chunk_hash
                {
                    if !self.map_hash_write.contains_key(&chunk_hash)
                    {
                        let mut chunk_hash2: [u8; HASH_SIZE] = [0; HASH_SIZE];
                        chunk_hash2.clone_from_slice(&chunk_hash);
                        self.map_hash_write.insert(chunk_hash2, Vec::new());
                    }
                    self.map_hash_write.get_mut(&chunk_hash).unwrap().push((fid, chunk_id));
                }
                self.update_left.remove(&(fid, chunk_id));
            }
        }
        return self.update_left.is_empty();
    }

    pub fn process_binary_data(&mut self, chunk: &Vec<u8>)
    {
        let mut chunk_hash: [u8; HASH_SIZE] = [0; HASH_SIZE];
        chunk_hash.clone_from_slice(&chunk[0..HASH_SIZE]);
        let mut uncompressed_chunk: Vec<u8> = Vec::new();
        uncompressed_chunk.extend_from_slice(&lz4::decompress(&chunk[HASH_SIZE..chunk.len()]).unwrap().as_slice());
        let mut hash_checker = Keccak::new_sha3_256();
        hash_checker.update(uncompressed_chunk.as_slice());
        let mut hash_result: [u8; HASH_SIZE] = [0; HASH_SIZE];
        hash_checker.finalize(&mut hash_result);
        if hash_result != chunk_hash
        {
            println!("WARNING!!! Received garbage data, discarding");
            return;
        }
        self.process_chunk(&chunk_hash, &uncompressed_chunk);
    }

    pub fn process_chunk(&mut self, chunk_hash: &[u8; HASH_SIZE], chunk: &Vec<u8>)
    {
        if self.read_only
        {
            panic!("Writing on read-only files!");
        }
        if !self.map_hash_write.contains_key(chunk_hash)
        {
            return;
        }
        {
            let vec_mapped = self.map_hash_write.get(chunk_hash).unwrap();
            for i in vec_mapped
            {
                let &(unmapped_fid, chunk_id) = i;
                if !self.file_index_map.contains_key(&unmapped_fid)
                {
                    continue;
                }
                let mapped_fid = self.file_index_map.get(&unmapped_fid).unwrap().clone();
                self.data[mapped_fid].write_chunk(chunk_id as usize, chunk);
            }
        }
        self.map_hash_write.remove(chunk_hash);
    }

    pub fn get_binary_data(&mut self, chunk_hash: &[u8; HASH_SIZE]) -> Option<Vec<u8>>
    {
        let chunk_wrap = self.get_chunk(chunk_hash);
        if chunk_wrap.is_none()
        {
            return None;
        }
        let chunk = chunk_wrap.unwrap();
        let mut v: Vec<u8> = Vec::new();
        let mut buffer: [u8; 128] = [0; 128];
        // Magic number
        BigEndian::write_u32(&mut buffer[0..4], MAGIC_NUMBER);
        v.extend_from_slice(&buffer[0..4]);
        // Protocol version
        BigEndian::write_u16(&mut buffer[0..2], PROTOCOL_VERSION);
        v.extend_from_slice(&buffer[0..2]);
        // Action
        v.push(ACTION_SEND_DATA);
        // Chunk hash
        v.extend_from_slice(chunk_hash);
        // Data
        v.extend_from_slice(&lz4::compress(&chunk).as_slice());
        if v.len() > 65000
        {
            panic!("Compression is doing some damage!");
        }
        return Some(v);
    }

    pub fn get_chunk(&mut self, chunk_hash: &[u8; HASH_SIZE]) -> Option<Vec<u8>>
    {
        if !self.map_hash_read.contains_key(chunk_hash)
        {
            return None;
        }
        let &(i, j) = self.map_hash_read.get(chunk_hash).unwrap();
        return Some(self.data[i as usize].read_chunk(j as usize));
    }
}

impl FileDescription
{
    pub fn new(diskfile: &DiskFile, _id: u8) -> FileDescription
    {
        let mut fd = FileDescription {
            id: _id,
            name: diskfile.get_file_name(),
            name_hash: diskfile.get_name_hash(),
            hash: diskfile.get_file_hash(),
            chunk: Vec::new(),
            last_chunk_size: diskfile.get_chunk_size(diskfile.get_num_chunks() - 1) as u16,
        };
        for i in 0..diskfile.get_num_chunks()
        {
            fd.chunk.push(diskfile.get_chunk_hash(i));
        }
        return fd;
    }
}
<|endoftext|>


<commit_before>/*
Module: sort

Sorting methods
*/
import vec::{len, slice};

export merge_sort;
export quick_sort;
export quick_sort3;

/* Type: le */
type le<T> = fn(T, T) -> bool;

/*
Function: merge_sort

Merge sort. Returns a new vector containing the sorted list.

Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort.
*/
fn merge_sort<T: copy>(le: le<T>, v: [const T]) -> [T] {
    fn merge<T: copy>(le: le<T>, a: [T], b: [T]) -> [T] {
        let rs: [T] = [];
        let a_len: uint = len::<T>(a);
        let a_ix: uint = 0u;
        let b_len: uint = len::<T>(b);
        let b_ix: uint = 0u;
        while a_ix < a_len && b_ix < b_len {
            if le(a[a_ix], b[b_ix]) {
                rs += [a[a_ix]];
                a_ix += 1u;
            } else { rs += [b[b_ix]]; b_ix += 1u; }
        }
        rs += slice::<T>(a, a_ix, a_len);
        rs += slice::<T>(b, b_ix, b_len);
        ret rs;
    }
    let v_len: uint = len::<T>(v);
    if v_len == 0u { ret []; }
    if v_len == 1u { ret [v[0]]; }
    let mid: uint = v_len / 2u;
    let a: [T] = slice::<T>(v, 0u, mid);
    let b: [T] = slice::<T>(v, mid, v_len);
    ret merge::<T>(le, merge_sort::<T>(le, a), merge_sort::<T>(le, b));
}

fn part<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
                right: uint, pivot: uint) -> uint {
    let pivot_value = arr[pivot];
    arr[pivot] <-> arr[right];
    let storage_index: uint = left;
    let i: uint = left;
    while i < right {
        if compare_func(copy arr[i], pivot_value) {
            arr[i] <-> arr[storage_index];
            storage_index += 1u;
        }
        i += 1u;
    }
    arr[storage_index] <-> arr[right];
    ret storage_index;
}

fn qsort<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
             right: uint) {
    if right > left {
        let pivot = (left + right) / 2u;
        let new_pivot = part::<T>(compare_func, arr, left, right, pivot);
        if new_pivot != 0u {
            // Need to do this check before recursing due to overflow
            qsort::<T>(compare_func, arr, left, new_pivot - 1u);
        }
        qsort::<T>(compare_func, arr, new_pivot + 1u, right);
    }
}

/*
Function: quick_sort

Quicksort. Sorts a mutable vector in place.

Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort.
*/
fn quick_sort<T: copy>(compare_func: le<T>, arr: [mutable T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
}

fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                  arr: [mutable T], left: int, right: int) {
    if right <= left { ret; }
    let v: T = arr[right];
    let i: int = left - 1;
    let j: int = right;
    let p: int = i;
    let q: int = j;
    while true {
        i += 1;
        while compare_func_lt(copy arr[i], v) { i += 1; }
        j -= 1;
        while compare_func_lt(v, copy arr[j]) {
            if j == left { break; }
            j -= 1;
        }
        if i >= j { break; }
        arr[i] <-> arr[j];
        if compare_func_eq(copy arr[i], v) {
            p += 1;
            arr[p] <-> arr[i];
        }
        if compare_func_eq(v, copy arr[j]) {
            q -= 1;
            arr[j] <-> arr[q];
        }
    }
    arr[i] <-> arr[right];
    j = i - 1;
    i += 1;
    let k: int = left;
    while k < p {
        arr[k] <-> arr[j];
        k += 1;
        j -= 1;
        if k == len::<T>(arr) as int { break; }
    }
    k = right - 1;
    while k > q {
        arr[i] <-> arr[k];
        k -= 1;
        i += 1;
        if k == 0 { break; }
    }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, left, j);
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
}

// FIXME: This should take lt and eq types
/*
Function: quick_sort3

Fancy quicksort. Sorts a mutable vector in place.

Based on algorithm presented by Sedgewick and Bentley
<http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf>.
According to these slides this is the algorithm of choice for
'randomly ordered keys, abstract compare' & 'small number of key values'.

This is an unstable sort.
*/
fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                       arr: [mutable T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
                (len::<T>(arr) as int) - 1);
}

#[cfg(test)]
mod test_qsort3 {
    fn check_sort(v1: [mutable int], v2: [mutable int]) {
        let len = vec::len::<int>(v1);
        fn lt(&&a: int, &&b: int) -> bool { ret a < b; }
        fn equal(&&a: int, &&b: int) -> bool { ret a == b; }
        let f1 = lt;
        let f2 = equal;
        quick_sort3::<int>(f1, f2, v1);
        let i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mutable 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mutable 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mutable 1, 1, 1];
            let v2 = [mutable 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mutable int] = [mutable];
            let v2: [mutable int] = [mutable];
            check_sort(v1, v2);
        }
        { let v1 = [mutable 9]; let v2 = [mutable 9]; check_sort(v1, v2); }
        {
            let v1 = [mutable 9, 3, 3, 3, 9];
            let v2 = [mutable 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }
}

#[cfg(test)]
mod test_qsort {
    fn check_sort(v1: [mutable int], v2: [mutable int]) {
        let len = vec::len::<int>(v1);
        fn leual(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = leual;
        quick_sort::<int>(f, v1);
        let i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mutable 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mutable 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mutable 1, 1, 1];
            let v2 = [mutable 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mutable int] = [mutable];
            let v2: [mutable int] = [mutable];
            check_sort(v1, v2);
        }
        { let v1 = [mutable 9]; let v2 = [mutable 9]; check_sort(v1, v2); }
        {
            let v1 = [mutable 9, 3, 3, 3, 9];
            let v2 = [mutable 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    // Regression test for #750
    #[test]
    fn test_simple() {
        let names = [mutable 2, 1, 3];

        let expected = [1, 2, 3];

        fn le(&&a: int, &&b: int) -> bool { int::le(a, b) }
        sort::quick_sort(le, names);

        let immut_names = vec::from_mut(names);

        let pairs = vec::zip(expected, immut_names);
        for (a, b) in pairs { #debug("%d %d", a, b); assert (a == b); }
    }
}

#[cfg(test)]
mod tests {

    fn check_sort(v1: [int], v2: [int]) {
        let len = vec::len::<int>(v1);
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = le;
        let v3 = merge_sort::<int>(f, v1);
        let i = 0u;
        while i < len {
            log(debug, v3[i]);
            assert (v3[i] == v2[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        { let v1 = [1, 1, 1]; let v2 = [1, 1, 1]; check_sort(v1, v2); }
        { let v1: [int] = []; let v2: [int] = []; check_sort(v1, v2); }
        { let v1 = [9]; let v2 = [9]; check_sort(v1, v2); }
        {
            let v1 = [9, 3, 3, 3, 9];
            let v2 = [3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    #[test]
    fn test_merge_sort_mutable() {
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let v1 = [mutable 3, 2, 1];
        let v2 = merge_sort(le, v1);
        assert v2 == [1, 2, 3];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>std: Make merge_sort faster<commit_after>/*
Module: sort

Sorting methods
*/
import vec::len;

export merge_sort;
export quick_sort;
export quick_sort3;

/* Type: le */
type le<T> = fn(T, T) -> bool;

/*
Function: merge_sort

Merge sort. Returns a new vector containing the sorted list.

Has worst case O(n log n) performance, best case O(n), but
is not space efficient. This is a stable sort.
*/
fn merge_sort<T: copy>(le: le<T>, v: [const T]) -> [T] {
    type slice = (uint, uint);

    ret merge_sort_(le, v, (0u, len(v)));

    fn merge_sort_<T: copy>(le: le<T>, v: [const T], slice: slice) -> [T] {
        let begin = tuple::first(slice);
        let end = tuple::second(slice);

        let v_len = end - begin;
        if v_len == 0u { ret []; }
        if v_len == 1u { ret [v[begin]]; }

        let mid = v_len / 2u + begin;
        let a = (begin, mid);
        let b = (mid, end);
        ret merge(le, merge_sort_(le, v, a), merge_sort_(le, v, b));
    }

    fn merge<T: copy>(le: le<T>, a: [T], b: [T]) -> [T] {
        let rs = [];
        vec::reserve(rs, len(a) + len(b));
        let a_len = len(a);
        let a_ix = 0u;
        let b_len = len(b);
        let b_ix = 0u;
        while a_ix < a_len && b_ix < b_len {
            if le(a[a_ix], b[b_ix]) {
                rs += [a[a_ix]];
                a_ix += 1u;
            } else { rs += [b[b_ix]]; b_ix += 1u; }
        }
        rs += vec::slice(a, a_ix, a_len);
        rs += vec::slice(b, b_ix, b_len);
        ret rs;
    }
}

fn part<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
                right: uint, pivot: uint) -> uint {
    let pivot_value = arr[pivot];
    arr[pivot] <-> arr[right];
    let storage_index: uint = left;
    let i: uint = left;
    while i < right {
        if compare_func(copy arr[i], pivot_value) {
            arr[i] <-> arr[storage_index];
            storage_index += 1u;
        }
        i += 1u;
    }
    arr[storage_index] <-> arr[right];
    ret storage_index;
}

fn qsort<T: copy>(compare_func: le<T>, arr: [mutable T], left: uint,
             right: uint) {
    if right > left {
        let pivot = (left + right) / 2u;
        let new_pivot = part::<T>(compare_func, arr, left, right, pivot);
        if new_pivot != 0u {
            // Need to do this check before recursing due to overflow
            qsort::<T>(compare_func, arr, left, new_pivot - 1u);
        }
        qsort::<T>(compare_func, arr, new_pivot + 1u, right);
    }
}

/*
Function: quick_sort

Quicksort. Sorts a mutable vector in place.

Has worst case O(n^2) performance, average case O(n log n).
This is an unstable sort.
*/
fn quick_sort<T: copy>(compare_func: le<T>, arr: [mutable T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort::<T>(compare_func, arr, 0u, len::<T>(arr) - 1u);
}

fn qsort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                  arr: [mutable T], left: int, right: int) {
    if right <= left { ret; }
    let v: T = arr[right];
    let i: int = left - 1;
    let j: int = right;
    let p: int = i;
    let q: int = j;
    while true {
        i += 1;
        while compare_func_lt(copy arr[i], v) { i += 1; }
        j -= 1;
        while compare_func_lt(v, copy arr[j]) {
            if j == left { break; }
            j -= 1;
        }
        if i >= j { break; }
        arr[i] <-> arr[j];
        if compare_func_eq(copy arr[i], v) {
            p += 1;
            arr[p] <-> arr[i];
        }
        if compare_func_eq(v, copy arr[j]) {
            q -= 1;
            arr[j] <-> arr[q];
        }
    }
    arr[i] <-> arr[right];
    j = i - 1;
    i += 1;
    let k: int = left;
    while k < p {
        arr[k] <-> arr[j];
        k += 1;
        j -= 1;
        if k == len::<T>(arr) as int { break; }
    }
    k = right - 1;
    while k > q {
        arr[i] <-> arr[k];
        k -= 1;
        i += 1;
        if k == 0 { break; }
    }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, left, j);
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, i, right);
}

// FIXME: This should take lt and eq types
/*
Function: quick_sort3

Fancy quicksort. Sorts a mutable vector in place.

Based on algorithm presented by Sedgewick and Bentley
<http://www.cs.princeton.edu/~rs/talks/QuicksortIsOptimal.pdf>.
According to these slides this is the algorithm of choice for
'randomly ordered keys, abstract compare' & 'small number of key values'.

This is an unstable sort.
*/
fn quick_sort3<T: copy>(compare_func_lt: le<T>, compare_func_eq: le<T>,
                       arr: [mutable T]) {
    if len::<T>(arr) == 0u { ret; }
    qsort3::<T>(compare_func_lt, compare_func_eq, arr, 0,
                (len::<T>(arr) as int) - 1);
}

#[cfg(test)]
mod test_qsort3 {
    fn check_sort(v1: [mutable int], v2: [mutable int]) {
        let len = vec::len::<int>(v1);
        fn lt(&&a: int, &&b: int) -> bool { ret a < b; }
        fn equal(&&a: int, &&b: int) -> bool { ret a == b; }
        let f1 = lt;
        let f2 = equal;
        quick_sort3::<int>(f1, f2, v1);
        let i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mutable 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mutable 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mutable 1, 1, 1];
            let v2 = [mutable 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mutable int] = [mutable];
            let v2: [mutable int] = [mutable];
            check_sort(v1, v2);
        }
        { let v1 = [mutable 9]; let v2 = [mutable 9]; check_sort(v1, v2); }
        {
            let v1 = [mutable 9, 3, 3, 3, 9];
            let v2 = [mutable 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }
}

#[cfg(test)]
mod test_qsort {
    fn check_sort(v1: [mutable int], v2: [mutable int]) {
        let len = vec::len::<int>(v1);
        fn leual(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = leual;
        quick_sort::<int>(f, v1);
        let i = 0u;
        while i < len {
            log(debug, v2[i]);
            assert (v2[i] == v1[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [mutable 3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [mutable 2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        {
            let v1 = [mutable 1, 1, 1];
            let v2 = [mutable 1, 1, 1];
            check_sort(v1, v2);
        }
        {
            let v1: [mutable int] = [mutable];
            let v2: [mutable int] = [mutable];
            check_sort(v1, v2);
        }
        { let v1 = [mutable 9]; let v2 = [mutable 9]; check_sort(v1, v2); }
        {
            let v1 = [mutable 9, 3, 3, 3, 9];
            let v2 = [mutable 3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    // Regression test for #750
    #[test]
    fn test_simple() {
        let names = [mutable 2, 1, 3];

        let expected = [1, 2, 3];

        fn le(&&a: int, &&b: int) -> bool { int::le(a, b) }
        sort::quick_sort(le, names);

        let immut_names = vec::from_mut(names);

        let pairs = vec::zip(expected, immut_names);
        for (a, b) in pairs { #debug("%d %d", a, b); assert (a == b); }
    }
}

#[cfg(test)]
mod tests {

    fn check_sort(v1: [int], v2: [int]) {
        let len = vec::len::<int>(v1);
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let f = le;
        let v3 = merge_sort::<int>(f, v1);
        let i = 0u;
        while i < len {
            log(debug, v3[i]);
            assert (v3[i] == v2[i]);
            i += 1u;
        }
    }

    #[test]
    fn test() {
        {
            let v1 = [3, 7, 4, 5, 2, 9, 5, 8];
            let v2 = [2, 3, 4, 5, 5, 7, 8, 9];
            check_sort(v1, v2);
        }
        { let v1 = [1, 1, 1]; let v2 = [1, 1, 1]; check_sort(v1, v2); }
        { let v1: [int] = []; let v2: [int] = []; check_sort(v1, v2); }
        { let v1 = [9]; let v2 = [9]; check_sort(v1, v2); }
        {
            let v1 = [9, 3, 3, 3, 9];
            let v2 = [3, 3, 3, 9, 9];
            check_sort(v1, v2);
        }
    }

    #[test]
    fn test_merge_sort_mutable() {
        fn le(&&a: int, &&b: int) -> bool { ret a <= b; }
        let v1 = [mutable 3, 2, 1];
        let v2 = merge_sort(le, v1);
        assert v2 == [1, 2, 3];
    }
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous helpers for common patterns.

use cast;
use ptr;
use prelude::*;
use unstable::intrinsics;

/// The identity function.
#[inline(always)]
pub fn id<T>(x: T) -> T { x }

/// Ignores a value.
#[inline(always)]
pub fn ignore<T>(_x: T) { }

/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
/// original value of `*ptr`.
///
/// NB: This function accepts `@mut T` and not `&mut T` to avoid
/// an obvious borrowck hazard. Typically passing in `&mut T` will
/// cause borrow check errors because it freezes whatever location
/// that `&mut T` is stored in (either statically or dynamically).
#[inline(always)]
pub fn with<T,R>(
    ptr: @mut T,
    value: T,
    op: &fn() -> R) -> R
{
    let prev = replace(ptr, value);
    let result = op();
    *ptr = prev;
    return result;
}

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline(always)]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut tmp: T = intrinsics::uninit();
        let t: *mut T = &mut tmp;

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping_memory(t, x, 1);
        ptr::copy_nonoverlapping_memory(x, y, 1);
        ptr::copy_nonoverlapping_memory(y, t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(tmp);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline(always)]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// A non-copyable dummy type.
pub struct NonCopyable {
    priv i: (),
}

impl NonCopyable {
    /// Creates a dummy non-copyable structure and returns it for use.
    pub fn new() -> NonCopyable { NonCopyable { i: () } }
}

impl Drop for NonCopyable {
    fn finalize(&self) { }
}

/// A type with no inhabitants
pub enum Void { }

impl Void {
    /// A utility function for ignoring this uninhabited type
    pub fn uninhabited(self) -> ! {
        match self {
            // Nothing to match on
        }
    }
}

/**
A utility function for indicating unreachable code. It will fail if
executed. This is occasionally useful to put after loops that never
terminate normally, but instead directly return from a function.

# Example

~~~ {.rust}
fn choose_weighted_item(v: &[Item]) -> Item {
    assert!(!v.is_empty());
    let mut so_far = 0u;
    for v.each |item| {
        so_far += item.weight;
        if so_far > 100 {
            return item;
        }
    }
    // The above loop always returns, so we must hint to the
    // type checker that it isn't possible to get down here
    util::unreachable();
}
~~~

*/
pub fn unreachable() -> ! {
    fail!("internal error: entered unreachable code");
}

#[cfg(test)]
mod tests {
    use option::{None, Some};
    use util::{Void, NonCopyable, id, replace, swap};
    use either::{Either, Left, Right};

    #[test]
    pub fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[(5, false)];
        //FIXME #3387 assert!(x.eq(id(copy x)));
        let y = copy x;
        assert!(x.eq(&id(y)));
    }
    #[test]
    pub fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }
    #[test]
    pub fn test_replace() {
        let mut x = Some(NonCopyable::new());
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }
    #[test]
    pub fn test_uninhabited() {
        let could_only_be_coin : Either <Void, ()> = Right (());
        match could_only_be_coin {
            Right (coin) => coin,
            Left (is_void) => is_void.uninhabited ()
        }
    }
}
<commit_msg>make util::NonCopyable a unit struct instead of a struct with a unit<commit_after>// Copyright 2012-2013 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Miscellaneous helpers for common patterns.

use cast;
use ptr;
use prelude::*;
use unstable::intrinsics;

/// The identity function.
#[inline(always)]
pub fn id<T>(x: T) -> T { x }

/// Ignores a value.
#[inline(always)]
pub fn ignore<T>(_x: T) { }

/// Sets `*ptr` to `new_value`, invokes `op()`, and then restores the
/// original value of `*ptr`.
///
/// NB: This function accepts `@mut T` and not `&mut T` to avoid
/// an obvious borrowck hazard. Typically passing in `&mut T` will
/// cause borrow check errors because it freezes whatever location
/// that `&mut T` is stored in (either statically or dynamically).
#[inline(always)]
pub fn with<T,R>(
    ptr: @mut T,
    value: T,
    op: &fn() -> R) -> R
{
    let prev = replace(ptr, value);
    let result = op();
    *ptr = prev;
    return result;
}

/**
 * Swap the values at two mutable locations of the same type, without
 * deinitialising or copying either one.
 */
#[inline(always)]
pub fn swap<T>(x: &mut T, y: &mut T) {
    unsafe {
        // Give ourselves some scratch space to work with
        let mut tmp: T = intrinsics::uninit();
        let t: *mut T = &mut tmp;

        // Perform the swap, `&mut` pointers never alias
        ptr::copy_nonoverlapping_memory(t, x, 1);
        ptr::copy_nonoverlapping_memory(x, y, 1);
        ptr::copy_nonoverlapping_memory(y, t, 1);

        // y and t now point to the same thing, but we need to completely forget `tmp`
        // because it's no longer relevant.
        cast::forget(tmp);
    }
}

/**
 * Replace the value at a mutable location with a new one, returning the old
 * value, without deinitialising or copying either one.
 */
#[inline(always)]
pub fn replace<T>(dest: &mut T, mut src: T) -> T {
    swap(dest, &mut src);
    src
}

/// A non-copyable dummy type.
pub struct NonCopyable;

impl NonCopyable {
    /// Creates a dummy non-copyable structure and returns it for use.
    pub fn new() -> NonCopyable { NonCopyable }
}

impl Drop for NonCopyable {
    fn finalize(&self) { }
}

/// A type with no inhabitants
pub enum Void { }

impl Void {
    /// A utility function for ignoring this uninhabited type
    pub fn uninhabited(self) -> ! {
        match self {
            // Nothing to match on
        }
    }
}

/**
A utility function for indicating unreachable code. It will fail if
executed. This is occasionally useful to put after loops that never
terminate normally, but instead directly return from a function.

# Example

~~~ {.rust}
fn choose_weighted_item(v: &[Item]) -> Item {
    assert!(!v.is_empty());
    let mut so_far = 0u;
    for v.each |item| {
        so_far += item.weight;
        if so_far > 100 {
            return item;
        }
    }
    // The above loop always returns, so we must hint to the
    // type checker that it isn't possible to get down here
    util::unreachable();
}
~~~

*/
pub fn unreachable() -> ! {
    fail!("internal error: entered unreachable code");
}

#[cfg(test)]
mod tests {
    use option::{None, Some};
    use util::{Void, NonCopyable, id, replace, swap};
    use either::{Either, Left, Right};

    #[test]
    pub fn identity_crisis() {
        // Writing a test for the identity function. How did it come to this?
        let x = ~[(5, false)];
        //FIXME #3387 assert!(x.eq(id(copy x)));
        let y = copy x;
        assert!(x.eq(&id(y)));
    }
    #[test]
    pub fn test_swap() {
        let mut x = 31337;
        let mut y = 42;
        swap(&mut x, &mut y);
        assert_eq!(x, 42);
        assert_eq!(y, 31337);
    }
    #[test]
    pub fn test_replace() {
        let mut x = Some(NonCopyable::new());
        let y = replace(&mut x, None);
        assert!(x.is_none());
        assert!(y.is_some());
    }
    #[test]
    pub fn test_uninhabited() {
        let could_only_be_coin : Either <Void, ()> = Right (());
        match could_only_be_coin {
            Right (coin) => coin,
            Left (is_void) => is_void.uninhabited ()
        }
    }
}
<|endoftext|>


<commit_before>#![feature(std_misc)]
extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread::Thread;

use postgres::SslMode;
use r2d2_postgres::PostgresConnectionManager;

#[test]
fn test_basic() {
    let manager = PostgresConnectionManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config::builder().pool_size(2).build();
    let handler = Box::new(r2d2::NoopErrorHandler);
    let pool = Arc::new(r2d2::Pool::new(config, manager, handler).unwrap());

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = Thread::scoped(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = Thread::scoped(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join().ok().unwrap();
    t2.join().ok().unwrap();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = PostgresConnectionManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config::builder().pool_size(1).test_on_check_out(true).build();
    let handler = Box::new(r2d2::NoopErrorHandler);
    let pool = r2d2::Pool::new(config, manager, handler).unwrap();

    pool.get().unwrap();
}
<commit_msg>Fix test breakage<commit_after>extern crate postgres;
extern crate r2d2;
extern crate r2d2_postgres;

use std::sync::Arc;
use std::sync::mpsc;
use std::thread;

use postgres::SslMode;
use r2d2_postgres::PostgresConnectionManager;

#[test]
fn test_basic() {
    let manager = PostgresConnectionManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config::builder().pool_size(2).build();
    let handler = Box::new(r2d2::NoopErrorHandler);
    let pool = Arc::new(r2d2::Pool::new(config, manager, handler).unwrap());

    let (s1, r1) = mpsc::channel();
    let (s2, r2) = mpsc::channel();

    let pool1 = pool.clone();
    let t1 = thread::scoped(move || {
        let conn = pool1.get().unwrap();
        s1.send(()).unwrap();
        r2.recv().unwrap();
        drop(conn);
    });

    let pool2 = pool.clone();
    let t2 = thread::scoped(move || {
        let conn = pool2.get().unwrap();
        s2.send(()).unwrap();
        r1.recv().unwrap();
        drop(conn);
    });

    t1.join();
    t2.join();

    pool.get().unwrap();
}

#[test]
fn test_is_valid() {
    let manager = PostgresConnectionManager::new("postgres://postgres@localhost", SslMode::None);
    let config = r2d2::Config::builder().pool_size(1).test_on_check_out(true).build();
    let handler = Box::new(r2d2::NoopErrorHandler);
    let pool = r2d2::Pool::new(config, manager, handler).unwrap();

    pool.get().unwrap();
}
<|endoftext|>


<commit_before>extern crate r2d2;

use std::sync::Mutex;
use std::default::Default;

mod config;

#[deriving(Show, PartialEq)]
struct FakeConnection;

#[deriving(Default)]
struct OkManager;

impl r2d2::PoolManager<FakeConnection, ()> for OkManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        Ok(FakeConnection)
    }

    fn is_valid(&self, _: &FakeConnection) -> bool {
        true
    }
}

struct NthConnectFailManager {
    n: Mutex<uint>,
}

impl r2d2::PoolManager<FakeConnection, ()> for NthConnectFailManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        let mut n = self.n.lock();
        if *n > 0 {
            *n -= 1;
            Ok(FakeConnection)
        } else {
            Err(())
        }
    }

    fn is_valid(&self, _: &FakeConnection) -> bool {
        true
    }
}

#[test]
fn test_pool_size_ok() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(5) };
    assert!(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).is_ok());
}

#[test]
fn test_pool_size_err() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(4) };
    assert_eq!(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).err().unwrap(),
               r2d2::ConnectionError(()));
}

#[test]
fn test_missing_replace() {
    fn hack_rust_14875(pool: &r2d2::Pool<FakeConnection, (), OkManager, r2d2::NoopErrorHandler>) {
        pool.get().unwrap();
    }

    let pool = r2d2::Pool::new(Default::default(), OkManager, r2d2::NoopErrorHandler).unwrap();
    hack_rust_14875(&pool);
}

#[test]
fn test_acquire_release() {
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let pool = r2d2::Pool::new(config, OkManager, r2d2::NoopErrorHandler).unwrap();

    let conn1 = pool.get().unwrap();
    let conn2 = pool.get().unwrap();
    drop(conn1);
    let conn3 = pool.get().unwrap();
    drop(conn2);
    drop(conn3);
}

#[test]
fn test_is_send_sync() {
    fn is_send_sync<T: Send+Sync>() {}
    is_send_sync::<r2d2::Pool<FakeConnection, (), OkManager, r2d2::NoopErrorHandler>>();
}
<commit_msg>Remove useless test<commit_after>extern crate r2d2;

use std::sync::Mutex;
use std::default::Default;

mod config;

#[deriving(Show, PartialEq)]
struct FakeConnection;

#[deriving(Default)]
struct OkManager;

impl r2d2::PoolManager<FakeConnection, ()> for OkManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        Ok(FakeConnection)
    }

    fn is_valid(&self, _: &FakeConnection) -> bool {
        true
    }
}

struct NthConnectFailManager {
    n: Mutex<uint>,
}

impl r2d2::PoolManager<FakeConnection, ()> for NthConnectFailManager {
    fn connect(&self) -> Result<FakeConnection, ()> {
        let mut n = self.n.lock();
        if *n > 0 {
            *n -= 1;
            Ok(FakeConnection)
        } else {
            Err(())
        }
    }

    fn is_valid(&self, _: &FakeConnection) -> bool {
        true
    }
}

#[test]
fn test_pool_size_ok() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(5) };
    assert!(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).is_ok());
}

#[test]
fn test_pool_size_err() {
    let config = r2d2::Config {
        pool_size: 5,
        ..Default::default()
    };
    let manager = NthConnectFailManager { n: Mutex::new(4) };
    assert_eq!(r2d2::Pool::new(config, manager, r2d2::NoopErrorHandler).err().unwrap(),
               r2d2::ConnectionError(()));
}

#[test]
fn test_acquire_release() {
    let config = r2d2::Config {
        pool_size: 2,
        ..Default::default()
    };
    let pool = r2d2::Pool::new(config, OkManager, r2d2::NoopErrorHandler).unwrap();

    let conn1 = pool.get().unwrap();
    let conn2 = pool.get().unwrap();
    drop(conn1);
    let conn3 = pool.get().unwrap();
    drop(conn2);
    drop(conn3);
}

#[test]
fn test_is_send_sync() {
    fn is_send_sync<T: Send+Sync>() {}
    is_send_sync::<r2d2::Pool<FakeConnection, (), OkManager, r2d2::NoopErrorHandler>>();
}
<|endoftext|>


<commit_before>//! this is the logging module for xtensis.

// this file is part of xtensis.

// this is the xtensis text editor; it edits text.
// copyright (c) 2016-2017  the xtensis developers

// this program is free software: you can redistribute it and/or
// modify it under the terms of the gnu general public license as
// published by the free software foundation, either version 3 of the
// license, or (at your option) any later version.

// this program is distributed in the hope that it will be useful, but
// without any warranty; without even the implied warranty of
// merchantability or fitness for a particular purpose.  see the gnu
// general public license for more details.

// you should have received a copy of the gnu general public license
// along with this program.  if not, see
// <http://www.gnu.org/licenses/>.

extern crate time;
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use slog::Drain;
use slog::Logger;

use utils::{get_pkg_name, get_version};

/// initialise the logger.
pub fn init_logger() -> Logger {
    let decorator = slog_term::TermDecorator::new().build();
    let drain = slog_term::FullFormat::new(decorator).build().fuse();
    let drain = slog_async::Async::new(drain).build().fuse();

    let root_logger = slog::Logger::root(drain,
                                         o!("version" => get_version(),
                                            "app" => get_pkg_name()));

    debug!(root_logger, "Logger initialised.");

    return root_logger;
}
<commit_msg>logging: simplify imports<commit_after>//! this is the logging module for xtensis.

// this file is part of xtensis.

// this is the xtensis text editor; it edits text.
// copyright (c) 2016-2017  the xtensis developers

// this program is free software: you can redistribute it and/or
// modify it under the terms of the gnu general public license as
// published by the free software foundation, either version 3 of the
// license, or (at your option) any later version.

// this program is distributed in the hope that it will be useful, but
// without any warranty; without even the implied warranty of
// merchantability or fitness for a particular purpose.  see the gnu
// general public license for more details.

// you should have received a copy of the gnu general public license
// along with this program.  if not, see
// <http://www.gnu.org/licenses/>.

extern crate time;
extern crate slog;
extern crate slog_term;
extern crate slog_async;

use self::slog_term::{TermDecorator, FullFormat};
use slog::{Drain, Logger};
use slog_async::Async;

use utils::{get_pkg_name, get_version};

/// Initialise the logger.
pub fn init_logger() -> Logger {
    let decorator = TermDecorator::new().build();
    let drain = FullFormat::new(decorator).build().fuse();
    let drain = Async::new(drain).build().fuse();

    let root_logger = Logger::root(drain,
                                   o!("version" => get_version(),
                                      "app" => get_pkg_name()));

    debug!(root_logger, "Logger initialised.");

    return root_logger;
}
<|endoftext|>


<commit_before>use super::{GitRepo, GitError};
use super::Manifest;

use std::fs::ReadDir;
use std::path::{Path, PathBuf};

struct ExploratoryMode {
    read_dir: Option<ReadDir>,
    pending: Vec<PathBuf>,
}

impl Iterator for ExploratoryMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        while self.pending.len() > 0 {
            {
                let iter = match self.read_dir {
                    Some(ref mut it) => it,
                    None => {
                        let current_dir = match self.pending.pop() {
                            Some(p) => p,
                            None => continue,
                        };

                        let read_result = current_dir.read_dir();

                        if let Err(_) = read_result {
                            continue;
                        }

                        let it = read_result.unwrap();
                        self.read_dir = Some(it);
                        self.read_dir.as_mut().unwrap()
                    }
                };

                while let Some(dir_entry) = iter.next() {
                    let entry = {
                        if !dir_entry.is_ok() {
                            continue;
                        }

                        dir_entry.unwrap()
                    };

                    match entry.file_type() {
                        Ok(t) => {
                            if !t.is_dir() {
                                continue;
                            }
                        }
                        Err(_) => continue,
                    }

                    let path = entry.path();

                    match path.file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    if name_str.starts_with(".") || name_str.starts_with("$") {
                                        continue;
                                    }
                                }
                                None => continue,
                            }
                        }
                        None => continue,
                    };

                    let repo = match GitRepo::new(&path) {
                        Ok(r) => r,
                        Err(GitError::OpenRepo) => {
                            self.pending.push(path.to_path_buf());
                            continue;
                        }
                        Err(_) => continue,
                    };

                    return Some(repo);
                }
            }

            self.read_dir = None;
        }

        None
    }
}

struct ManifestMode {}

impl Iterator for ManifestMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

enum RepoMode {
    Exploratory(ExploratoryMode),
    Manifest(ManifestMode),
}

impl Iterator for RepoMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            RepoMode::Exploratory(ref mut em) => em.next(),
            RepoMode::Manifest(ref mut mm) => mm.next(),
        }
    }
}

pub struct GitRepositories {
    mode: RepoMode,
}

impl GitRepositories {
    pub fn new(path: &Path) -> Self {
        let exp = ExploratoryMode {
            read_dir: None,
            pending: vec![path.to_owned()],
        };

        GitRepositories { mode: RepoMode::Exploratory(exp) }
    }

    pub fn from_manifest(manifest: &Manifest) -> Self {
        let man = ManifestMode {};

        GitRepositories { mode: RepoMode::Manifest(man) }
    }
}

impl Iterator for GitRepositories {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        self.mode.next()
    }
}<commit_msg>Fixed error where you could not run git plz on direct subfolders<commit_after>use super::{GitRepo, GitError};
use super::Manifest;

use std::fs::ReadDir;
use std::path::{Path, PathBuf};

struct ExploratoryMode {
    read_dir: Option<ReadDir>,
    pending: Vec<PathBuf>,
}

impl Iterator for ExploratoryMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        while self.pending.len() > 0 || self.read_dir.is_some() {
            {
                let iter = match self.read_dir {
                    Some(ref mut it) => it,
                    None => {
                        let current_dir = match self.pending.pop() {
                            Some(p) => p,
                            None => continue,
                        };

                        let read_result = current_dir.read_dir();

                        if let Err(_) = read_result {
                            continue;
                        }

                        let it = read_result.unwrap();
                        self.read_dir = Some(it);
                        self.read_dir.as_mut().unwrap()
                    }
                };

                while let Some(dir_entry) = iter.next() {
                    let entry = {
                        if !dir_entry.is_ok() {
                            continue;
                        }

                        dir_entry.unwrap()
                    };

                    match entry.file_type() {
                        Ok(t) => {
                            if !t.is_dir() {
                                continue;
                            }
                        }
                        Err(_) => continue,
                    }

                    let path = entry.path();

                    match path.file_name() {
                        Some(name) => {
                            match name.to_str() {
                                Some(name_str) => {
                                    if name_str.starts_with(".") || name_str.starts_with("$") {
                                        continue;
                                    }
                                }
                                None => continue,
                            }
                        }
                        None => continue,
                    };

                    let repo = match GitRepo::new(&path) {
                        Ok(r) => r,
                        Err(GitError::OpenRepo) => {
                            self.pending.push(path.to_path_buf());
                            continue;
                        }
                        Err(_) => continue,
                    };

                    return Some(repo);
                }
            }

            self.read_dir = None;
        }

        None
    }
}

struct ManifestMode {}

impl Iterator for ManifestMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        None
    }
}

enum RepoMode {
    Exploratory(ExploratoryMode),
    Manifest(ManifestMode),
}

impl Iterator for RepoMode {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        match *self {
            RepoMode::Exploratory(ref mut em) => em.next(),
            RepoMode::Manifest(ref mut mm) => mm.next(),
        }
    }
}

pub struct GitRepositories {
    mode: RepoMode,
}

impl GitRepositories {
    pub fn new(path: &Path) -> Self {
        let exp = ExploratoryMode {
            read_dir: None,
            pending: vec![path.to_owned()],
        };

        GitRepositories { mode: RepoMode::Exploratory(exp) }
    }

    pub fn from_manifest(manifest: &Manifest) -> Self {
        let man = ManifestMode {};

        GitRepositories { mode: RepoMode::Manifest(man) }
    }
}

impl Iterator for GitRepositories {
    type Item = GitRepo;

    fn next(&mut self) -> Option<Self::Item> {
        self.mode.next()
    }
}<|endoftext|>


<commit_before>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0
use anyhow::{ensure, format_err, Error, Result};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
use std::{convert::TryFrom, fmt, str::FromStr};

/// A registry of named chain IDs
/// Its main purpose is to improve human readability of reserved chain IDs in config files and CLI
/// When signing transactions for such chains, the numerical chain ID should still be used
/// (e.g. MAINNET has numeric chain ID 1, TESTNET has chain ID 2, etc)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum NamedChain {
    /// Users might accidentally initialize the ChainId field to 0, hence reserving ChainId 0 for accidental
    /// initialization.
    /// MAINNET is the Aptos mainnet production chain and is reserved for 1
    MAINNET = 1,
    // Even though these CHAIN IDs do not correspond to MAINNET, changing them should be avoided since they
    // can break test environments for various organisations.
    TESTNET = 2,
    DEVNET = 3,
    TESTING = 4,
    PREMAINNET = 5,
}

impl NamedChain {
    fn str_to_chain_id(s: &str) -> Result<ChainId> {
        // TODO implement custom macro that derives FromStr impl for enum (similar to aptos-core/common/num-variants)
        let reserved_chain = match s {
            "MAINNET" => NamedChain::MAINNET,
            "TESTNET" => NamedChain::TESTNET,
            "DEVNET" => NamedChain::DEVNET,
            "TESTING" => NamedChain::TESTING,
            "PREMAINNET" => NamedChain::PREMAINNET,
            _ => {
                return Err(format_err!("Not a reserved chain: {:?}", s));
            }
        };
        Ok(ChainId::new(reserved_chain.id()))
    }

    pub fn id(&self) -> u8 {
        *self as u8
    }

    pub fn from_chain_id(chain_id: &ChainId) -> Result<NamedChain, String> {
        match chain_id.id() {
            1 => Ok(NamedChain::MAINNET),
            2 => Ok(NamedChain::TESTNET),
            3 => Ok(NamedChain::DEVNET),
            4 => Ok(NamedChain::TESTING),
            5 => Ok(NamedChain::PREMAINNET),
            _ => Err(String::from("Not a named chain")),
        }
    }
}

/// Note: u7 in a u8 is uleb-compatible, and any usage of this should be aware
/// that this field maybe updated to be uleb64 in the future
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainId(u8);

pub fn deserialize_config_chain_id<'de, D>(
    deserializer: D,
) -> std::result::Result<ChainId, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChainIdVisitor;

    impl<'de> Visitor<'de> for ChainIdVisitor {
        type Value = ChainId;

        fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("ChainId as string or u8")
        }

        fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ChainId::from_str(value).map_err(serde::de::Error::custom)
        }

        fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(ChainId::new(
                u8::try_from(value).map_err(serde::de::Error::custom)?,
            ))
        }
    }

    deserializer.deserialize_any(ChainIdVisitor)
}

impl fmt::Debug for ChainId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

impl fmt::Display for ChainId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            NamedChain::from_chain_id(self)
                .map_or_else(|_| self.0.to_string(), |chain| chain.to_string())
        )
    }
}

impl fmt::Display for NamedChain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NamedChain::DEVNET => "DEVNET",
                NamedChain::TESTNET => "TESTNET",
                NamedChain::MAINNET => "MAINNET",
                NamedChain::TESTING => "TESTING",
                NamedChain::PREMAINNET => "PREMAINNET",
            }
        )
    }
}

impl Default for ChainId {
    fn default() -> Self {
        Self::test()
    }
}

impl FromStr for ChainId {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        ensure!(!s.is_empty(), "Cannot create chain ID from empty string");
        NamedChain::str_to_chain_id(s).or_else(|_err| {
            let value = s.parse::<u8>()?;
            ensure!(value > 0, "cannot have chain ID with 0");
            Ok(ChainId::new(value))
        })
    }
}

impl ChainId {
    pub fn new(id: u8) -> Self {
        assert!(id > 0, "cannot have chain ID with 0");
        Self(id)
    }

    pub fn id(&self) -> u8 {
        self.0
    }

    pub fn test() -> Self {
        ChainId::new(NamedChain::TESTING.id())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_chain_id_from_str() {
        assert!(ChainId::from_str("").is_err());
        assert!(ChainId::from_str("0").is_err());
        assert!(ChainId::from_str("256").is_err());
        assert!(ChainId::from_str("255255").is_err());
        assert_eq!(ChainId::from_str("TESTING").unwrap(), ChainId::test());
        assert_eq!(ChainId::from_str("255").unwrap(), ChainId::new(255));
    }
}
<commit_msg>[chain-id] Make chain id inputs case insensitive, add long lived testnet<commit_after>// Copyright (c) Aptos
// SPDX-License-Identifier: Apache-2.0
use anyhow::{ensure, format_err, Error, Result};
use serde::{de::Visitor, Deserialize, Deserializer, Serialize};
use std::{convert::TryFrom, fmt, str::FromStr};

/// A registry of named chain IDs
/// Its main purpose is to improve human readability of reserved chain IDs in config files and CLI
/// When signing transactions for such chains, the numerical chain ID should still be used
/// (e.g. MAINNET has numeric chain ID 1, TESTNET has chain ID 2, etc)
#[repr(u8)]
#[derive(Copy, Clone, Debug)]
pub enum NamedChain {
    /// Users might accidentally initialize the ChainId field to 0, hence reserving ChainId 0 for accidental
    /// initialization.
    /// MAINNET is the Aptos mainnet production chain and is reserved for 1
    MAINNET = 1,
    // Even though these CHAIN IDs do not correspond to MAINNET, changing them should be avoided since they
    // can break test environments for various organisations.
    TESTNET = 2,
    DEVNET = 3,
    TESTING = 4,
    PREMAINNET = 5,
}

const MAINNET: &str = "mainnet";
const TESTNET: &str = "testnet";
const DEVNET: &str = "devnet";
const TESTING: &str = "testing";
const PREMAINNET: &str = "premainnet";

impl NamedChain {
    fn str_to_chain_id(s: &str) -> Result<ChainId> {
        // TODO implement custom macro that derives FromStr impl for enum (similar to aptos-core/common/num-variants)
        let reserved_chain = match s.to_lowercase().as_str() {
            MAINNET => NamedChain::MAINNET,
            TESTNET => NamedChain::TESTNET,
            DEVNET => NamedChain::DEVNET,
            TESTING => NamedChain::TESTING,
            PREMAINNET => NamedChain::PREMAINNET,
            _ => {
                return Err(format_err!("Not a reserved chain: {:?}", s));
            }
        };
        Ok(ChainId::new(reserved_chain.id()))
    }

    pub fn id(&self) -> u8 {
        *self as u8
    }

    pub fn from_chain_id(chain_id: &ChainId) -> Result<NamedChain, String> {
        match chain_id.id() {
            1 => Ok(NamedChain::MAINNET),
            2 => Ok(NamedChain::TESTNET),
            3 => Ok(NamedChain::DEVNET),
            4 => Ok(NamedChain::TESTING),
            5 => Ok(NamedChain::PREMAINNET),
            _ => Err(String::from("Not a named chain")),
        }
    }
}

/// Note: u7 in a u8 is uleb-compatible, and any usage of this should be aware
/// that this field maybe updated to be uleb64 in the future
#[derive(Clone, Copy, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct ChainId(u8);

pub fn deserialize_config_chain_id<'de, D>(
    deserializer: D,
) -> std::result::Result<ChainId, D::Error>
where
    D: Deserializer<'de>,
{
    struct ChainIdVisitor;

    impl<'de> Visitor<'de> for ChainIdVisitor {
        type Value = ChainId;

        fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            f.write_str("ChainId as string or u8")
        }

        fn visit_str<E>(self, value: &str) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            ChainId::from_str(value).map_err(serde::de::Error::custom)
        }

        fn visit_u64<E>(self, value: u64) -> std::result::Result<Self::Value, E>
        where
            E: serde::de::Error,
        {
            Ok(ChainId::new(
                u8::try_from(value).map_err(serde::de::Error::custom)?,
            ))
        }
    }

    deserializer.deserialize_any(ChainIdVisitor)
}

impl fmt::Debug for ChainId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "{}", self)
    }
}

impl fmt::Display for ChainId {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            NamedChain::from_chain_id(self)
                .map_or_else(|_| self.0.to_string(), |chain| chain.to_string())
        )
    }
}

impl fmt::Display for NamedChain {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(
            f,
            "{}",
            match self {
                NamedChain::DEVNET => DEVNET,
                NamedChain::TESTNET => TESTNET,
                NamedChain::MAINNET => MAINNET,
                NamedChain::TESTING => TESTING,
                NamedChain::PREMAINNET => PREMAINNET,
            }
        )
    }
}

impl Default for ChainId {
    fn default() -> Self {
        Self::test()
    }
}

impl FromStr for ChainId {
    type Err = Error;

    fn from_str(s: &str) -> Result<Self> {
        ensure!(!s.is_empty(), "Cannot create chain ID from empty string");
        NamedChain::str_to_chain_id(s).or_else(|_err| {
            let value = s.parse::<u8>()?;
            ensure!(value > 0, "cannot have chain ID with 0");
            Ok(ChainId::new(value))
        })
    }
}

impl ChainId {
    pub fn new(id: u8) -> Self {
        assert!(id > 0, "cannot have chain ID with 0");
        Self(id)
    }

    pub fn id(&self) -> u8 {
        self.0
    }

    pub fn test() -> Self {
        ChainId::new(NamedChain::TESTING.id())
    }
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn test_chain_id_from_str() {
        assert!(ChainId::from_str("").is_err());
        assert!(ChainId::from_str("0").is_err());
        assert!(ChainId::from_str("256").is_err());
        assert!(ChainId::from_str("255255").is_err());
        assert_eq!(ChainId::from_str("TESTING").unwrap(), ChainId::test());
        assert_eq!(ChainId::from_str("255").unwrap(), ChainId::new(255));
    }
}
<|endoftext|>


<commit_before>//! Rectangles on the 2D character grid.

use vec::Vec2;

/// A non-empty rectangle on the 2D grid.
///
///
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Rect {
    top_left: Vec2,
    bottom_right: Vec2,
}

impl<T> From<T> for Rect
where
    T: Into<Vec2>,
{
    fn from(other: T) -> Self {
        // From a point, we can create a 1-by-1 rectangle.
        Self::from_size(other, (1, 1))
    }
}

impl Rect {
    /// Creates a new `Rect` with the given position and size.
    ///
    /// `size` must be non-zero in each axis.
    pub fn from_size<U, V>(top_left: U, size: V) -> Self
    where
        U: Into<Vec2>,
        V: Into<Vec2>,
    {
        let size = size.into();
        let top_left = top_left.into();
        assert!(size > Vec2::zero());

        let bottom_right = top_left + size.saturating_sub((1, 1));

        Self::from_corners(top_left, bottom_right)
    }

    /// Creates a new `Rect` from two corners.
    ///
    /// It can be any two opposite corners.
    pub fn from_corners<U, V>(a: U, b: V) -> Self
    where
        U: Into<Vec2>,
        V: Into<Vec2>,
    {
        let a = a.into();
        let b = b.into();

        let top_left = Vec2::min(a, b);
        let bottom_right = Vec2::max(a, b);

        Rect {
            top_left,
            bottom_right,
        }
    }

    /// Grow this rectangle if necessary to include `other`.
    pub fn expand_to<R>(&mut self, other: R)
    where
        R: Into<Rect>,
    {
        let other = other.into();

        self.top_left = self.top_left.or_min(other.top_left);
        self.bottom_right = self.bottom_right.or_max(other.bottom_right);
    }

    /// Returns a new rectangle that includes both `self` and `other`.
    pub fn expanded_to<R>(mut self, other: R) -> Self
    where
        R: Into<Rect>,
    {
        self.expand_to(other);
        self
    }

    /// Returns the size of the rectangle.
    pub fn size(self) -> Vec2 {
        self.bottom_right - self.top_left + (1, 1)
    }

    /// Returns the width of the rectangle.
    pub fn width(self) -> usize {
        self.size().x
    }

    /// Returns the height of the rectangle.
    pub fn height(self) -> usize {
        self.size().y
    }

    /// Returns the top-left corner.
    pub fn top_left(self) -> Vec2 {
        self.top_left
    }

    /// Returns the bottom-right corner.
    pub fn bottom_right(self) -> Vec2 {
        self.bottom_right
    }

    /// Returns the top-right corner.
    pub fn top_right(self) -> Vec2 {
        Vec2::new(self.right(), self.top())
    }

    /// Returns the bottom-left corner.
    pub fn bottom_left(self) -> Vec2 {
        Vec2::new(self.left(), self.bottom())
    }

    /// Returns the Y value of the top edge of the rectangle.
    pub fn top(self) -> usize {
        self.top_left.y
    }

    /// Returns the X value of the left edge of the rectangle.
    pub fn left(self) -> usize {
        self.top_left.x
    }

    /// Returns the X value of the right edge of the rectangle.
    pub fn right(self) -> usize {
        self.bottom_right.x
    }

    /// Returns the Y value of the botton edge of the rectangle.
    pub fn bottom(self) -> usize {
        self.bottom_right.y
    }

    /// Returns the surface (number of cells) covered by the rectangle.
    pub fn surface(self) -> usize {
        self.width() * self.height()
    }
}
<commit_msg>Add Rect::offset<commit_after>//! Rectangles on the 2D character grid.

use vec::Vec2;

/// A non-empty rectangle on the 2D grid.
///
///
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct Rect {
    top_left: Vec2,
    bottom_right: Vec2,
}

impl<T> From<T> for Rect
where
    T: Into<Vec2>,
{
    fn from(other: T) -> Self {
        // From a point, we can create a 1-by-1 rectangle.
        Self::from_size(other, (1, 1))
    }
}

impl Rect {
    /// Creates a new `Rect` with the given position and size.
    ///
    /// `size` must be non-zero in each axis.
    pub fn from_size<U, V>(top_left: U, size: V) -> Self
    where
        U: Into<Vec2>,
        V: Into<Vec2>,
    {
        let size = size.into();
        let top_left = top_left.into();
        assert!(size > Vec2::zero());

        let bottom_right = top_left + size.saturating_sub((1, 1));

        Self::from_corners(top_left, bottom_right)
    }

    /// Creates a new `Rect` from two corners.
    ///
    /// It can be any two opposite corners.
    pub fn from_corners<U, V>(a: U, b: V) -> Self
    where
        U: Into<Vec2>,
        V: Into<Vec2>,
    {
        let a = a.into();
        let b = b.into();

        let top_left = Vec2::min(a, b);
        let bottom_right = Vec2::max(a, b);

        Rect {
            top_left,
            bottom_right,
        }
    }

    /// Grow this rectangle if necessary to include `other`.
    pub fn expand_to<R>(&mut self, other: R)
    where
        R: Into<Rect>,
    {
        let other = other.into();

        self.top_left = self.top_left.or_min(other.top_left);
        self.bottom_right = self.bottom_right.or_max(other.bottom_right);
    }

    /// Returns a new rectangle that includes both `self` and `other`.
    pub fn expanded_to<R>(mut self, other: R) -> Self
    where
        R: Into<Rect>,
    {
        self.expand_to(other);
        self
    }

    /// Adds the given offset to this rectangle.
    pub fn offset<V>(&mut self, offset: V) where V: Into<Vec2> {
        let offset = offset.into();
        self.top_left = self.top_left + offset;
        self.bottom_right = self.bottom_right + offset;
    }

    /// Returns the size of the rectangle.
    pub fn size(self) -> Vec2 {
        self.bottom_right - self.top_left + (1, 1)
    }

    /// Returns the width of the rectangle.
    pub fn width(self) -> usize {
        self.size().x
    }

    /// Returns the height of the rectangle.
    pub fn height(self) -> usize {
        self.size().y
    }

    /// Returns the top-left corner.
    pub fn top_left(self) -> Vec2 {
        self.top_left
    }

    /// Returns the bottom-right corner.
    pub fn bottom_right(self) -> Vec2 {
        self.bottom_right
    }

    /// Returns the top-right corner.
    pub fn top_right(self) -> Vec2 {
        Vec2::new(self.right(), self.top())
    }

    /// Returns the bottom-left corner.
    pub fn bottom_left(self) -> Vec2 {
        Vec2::new(self.left(), self.bottom())
    }

    /// Returns the Y value of the top edge of the rectangle.
    pub fn top(self) -> usize {
        self.top_left.y
    }

    /// Returns the X value of the left edge of the rectangle.
    pub fn left(self) -> usize {
        self.top_left.x
    }

    /// Returns the X value of the right edge of the rectangle.
    pub fn right(self) -> usize {
        self.bottom_right.x
    }

    /// Returns the Y value of the botton edge of the rectangle.
    pub fn bottom(self) -> usize {
        self.bottom_right.y
    }

    /// Returns the surface (number of cells) covered by the rectangle.
    pub fn surface(self) -> usize {
        self.width() * self.height()
    }
}
<|endoftext|>