<commit_before>use std::cmp::Ordering;
use std::collections::HashMap;
use std::io::Write;
use std::io::Read;
use std::io::Cursor;

use byteorder::{BigEndian, ByteOrder};
use msgpack_coders::{Encoder,Decoder};
use rustc_serialize::Decodable;
use rustc_serialize::Encodable;

use super::block::Block;

const ENTRY_SIZE             : u32 = 4;
const SUB_BUCKET_HEADER_SIZE : u32 = 1024;
 // header size 1024 bytes / entry size 4 bytes
const MAX_SUB_BUCKETS        : u32 = SUB_BUCKET_HEADER_SIZE / ENTRY_SIZE;
const MAX_DATA_SIZE          : u32 = 4096 - SUB_BUCKET_HEADER_SIZE - super::HASH_FOOTER_SIZE - super::block::BLOCK_FOOTER_SIZE;

static CANT_GROW_ERR : &'static str = "We can't grow in this implementation so indexes past 256 are untenable";

#[derive(Copy, Clone)]
pub struct Entry {
    offset: u16,
    size: u16,
}

pub fn put_sub_bucket(block : &mut Block, index : u32, map : &HashMap<i32,i32>) -> Result<(), String> {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let buf : Vec<u8>;
    match encode_msgpack(map) {
        Ok(v)  => buf = v,
        Err(e) => return Err(e),
    }

    let size       = buf.len() as u16;
    let mut entry  = get_entry(&block, index);

    // Hard case - it doesn't fit, allocate new
    if size > entry.size {
        match find_space(&block, size) {
            Some(off) => entry.offset = off,
            None      => return Err("Ran out of disk space I guess".to_string()),
        }
    }

    entry.size = size;
    put_entry(block, index, entry);
    for (i, b) in buf.iter().enumerate() {
        block[i+(entry.offset as usize)] = *b;
    }

    Ok(())
}

pub fn del_sub_bucket(block : &mut Block, index : u32) {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    put_entry(block, index, Entry { offset: 0, size: 0 });
}

pub fn get_sub_bucket(block : &Block, index : u32) -> Result<Option<HashMap<i32,i32>>, String> {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let entry = get_entry(block, index);
    if entry.size == 0 {
        return Ok(None)
    }

    let offset = entry.offset as usize;
    let size = entry.size as usize;

    match decode_msgpack(&block[offset..offset+size]) {
        Ok(v)  => Ok(Some(v)),
        Err(e) => return Err(e),
    }
}

/// Put an entry to some index, panics on bad index
fn put_entry(block : &mut Block, index : u32, e : Entry) {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let i = (index * 4) as usize;
    let j = i + 2;

    BigEndian::write_u16(&mut block[i..i+2], e.offset);
    BigEndian::write_u16(&mut block[j..j+2], e.size);
}

/// Get an entry from an index, panics on bad index
fn get_entry(block : &Block, index : u32) -> Entry {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let i = (index * 4) as usize;
    let j = i + 2;

    Entry {
        offset: BigEndian::read_u16(&block[i..i+2]),
        size: BigEndian::read_u16(&block[j..j+2]),
    }
}

/// Find a offset in memory for our data length, or None
fn find_space(block : &Block, want_size : u16) -> Option<u16> {
    let mut next_offset = SUB_BUCKET_HEADER_SIZE as u16;
    let size = next_power_of_2(want_size);

    // Sort all the entries such that they're ordered by offset
    let mut entries : Vec<Entry> = BlockIterator::new(&block).collect();
    entries.sort();

    for e in entries {
        if e.size == 0 {
            continue;
        }

        if next_offset + size <= e.offset {
            break;
        }

        next_offset = e.offset + next_power_of_2(e.size);
    }

    if next_offset + size > MAX_DATA_SIZE as u16 {
        return None;
    }

    Some(next_offset)
}

/// Return a buffer with the serialized hash map in it.
fn encode_msgpack(map : &HashMap<i32,i32>) -> Result<Vec<u8>, String> {
    let mut buf: Vec<u8> = Vec::new();

    {
        let mut encoder = Encoder::new(&mut buf);
        if let Some(e) = map.encode(&mut encoder).err() {
            return Err(format!("error writing map: {}", e))
        }
    }

    Ok(buf)
}

/// Decode a serialized hash map from a slice
fn decode_msgpack(slice : &[u8]) -> Result<HashMap<i32,i32>, String> {
    let c = Cursor::new(slice);

    let mut decoder = Decoder::new(c);
    match Decodable::decode(&mut decoder) {
        Ok(h)  => return Ok(h),
        Err(e) => Err(format!("error reading map: {}", e)),
    }
}

/// Bit twiddling magic function.
///
/// Essentially continuously or's it with itself
/// moving bits down the row and once all the bits
/// are filled in it adds one to turn on the next
/// power of two bit.
fn next_power_of_2(from : u16) -> u16 {
    let mut n = from - 1;
    n |= n >> 1;
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    //n |= n >> 16; // Not needed since I've shrank the size of the integer
    n + 1
}

struct BlockIterator<'a> {
    i: u32,
    block: &'a [ u8; 4096 ],
}

impl<'a> BlockIterator<'a> {
    fn new(b : &Block) -> BlockIterator {
        BlockIterator {
            i: 0,
            block: b,
        }
    }
}

impl<'a> Iterator for BlockIterator<'a> {
    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        if self.i == 256 {
            return None
        }

        let entry = get_entry(self.block, self.i);
        self.i += 1;

        return Some(entry);
    }
}

// This chunk of code is pretty ridiculous. Haskell beats you here pretty hard Rust.
impl PartialOrd for Entry {
    fn partial_cmp(&self, other : &Entry) -> Option<Ordering> { self.offset.partial_cmp(&other.offset) }
}
impl PartialEq for Entry {
    fn eq(&self, other : &Entry) -> bool { self.offset.eq(&other.offset) }
}
impl Ord for Entry {
    fn cmp(&self, other : &Entry) -> Ordering { self.offset.cmp(&other.offset) }
}
impl Eq for Entry {}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use super::super::block::*;

    #[test]
    fn get_sub_bucket() {
        let mut b : Block = new_block!();

        let mut h = HashMap::new();
        h.insert(5, 6);
        h.insert(7, 8);

        super::put_sub_bucket(&mut b, 1, &h).unwrap();

        let h2 = super::get_sub_bucket(&b, 1).unwrap().unwrap();
        assert_eq!(h, h2);
    }

    #[test]
    fn put_sub_bucket() {
        let mut b : Block = new_block!();

        let mut h = HashMap::new();
        h.insert(5, 6);
        h.insert(7, 8);

        super::put_sub_bucket(&mut b, 0, &mut h).unwrap();
        super::put_sub_bucket(&mut b, 2, &mut h).unwrap();
    }

    #[test]
    fn get_entry() {
        let mut b : Block = new_block!();

        // write an entry at b[40] of size: 257, offset: 258
        b[40] = 1;
        b[41] = 1;
        b[42] = 1;
        b[43] = 2;

        let entry = super::get_entry(&b, 10);

        assert_eq!(entry.offset, 257);
        assert_eq!(entry.size, 258);
    }

    #[test]
    fn put_entry() {
        let mut b : Block = new_block!();
        let e = super::Entry { size: 257, offset: 258 };

        super::put_entry(&mut b, 10, e);

        let entry = super::get_entry(&b, 10);

        assert_eq!(entry.size, 257);
        assert_eq!(entry.offset, 258);
    }

    #[test]
    fn find_space() {
        let mut b : Block = new_block!();

        // If the entire space is taken error
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: super::MAX_DATA_SIZE as u16 });
        assert_eq!(super::find_space(&b, 9), None);
    }

    #[test]
    fn find_space_end() {
        let mut b : Block = new_block!();

        // If there's space at the end
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: 9 });
        super::put_entry(&mut b, 2, super::Entry { offset: 16, size: 25 });

        assert_eq!(super::find_space(&b, 28).unwrap(), 48);
    }

    #[test]
    fn find_space_middle() {
        let mut b : Block = new_block!();

        // If there's a chunk in between somewhere (out of order)
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: 9 });
        super::put_entry(&mut b, 1, super::Entry { offset: 64, size: 26 });
        super::put_entry(&mut b, 2, super::Entry { offset: 16, size: 25 });

        assert_eq!(super::find_space(&b, 9).unwrap(), 48);
        assert_eq!(super::find_space(&b, 28).unwrap(), 96);
    }

    #[test]
    fn next_power_of_2() {
        assert_eq!(super::next_power_of_2(1), 1);
        assert_eq!(super::next_power_of_2(3), 4);
        assert_eq!(super::next_power_of_2(5), 8);
        assert_eq!(super::next_power_of_2(6), 8);
        assert_eq!(super::next_power_of_2(11), 16);
        assert_eq!(super::next_power_of_2(17), 32);
    }

    #[test]
    fn iterators() {
        let b : Block = new_block!();
        let mut bi = super::BlockIterator::new(&b);

        let mut count = 0;
        for e in bi {
            count += 1;
        }

        bi = super::BlockIterator::new(&b);
        bi.collect::<Vec<super::Entry>>().sort();

        assert_eq!(count, super::MAX_SUB_BUCKETS);
    }

    #[test]
    fn sorting() {
        let mut b : Block = new_block!();

        super::put_entry(&mut b, 0, super::Entry { offset: 196, size: 16 });
        super::put_entry(&mut b, 1, super::Entry { offset: 16, size: 32 });
        super::put_entry(&mut b, 2, super::Entry { offset: 36, size: 32 });

        let mut entries : Vec<super::Entry> = super::BlockIterator::new(&b).collect();
        entries.sort();

        let offsets : Vec<u16> = entries.iter().map(|i| i.offset).collect();

        // There's going to be a lot of zeroes in here, cull them out
        assert_eq!(offsets[offsets.len()-3..], [16, 36, 196]);
    }
}
<commit_msg>Add del test for entry.<commit_after>use std::cmp::Ordering;
use std::collections::HashMap;
use std::io::Write;
use std::io::Read;
use std::io::Cursor;

use byteorder::{BigEndian, ByteOrder};
use msgpack_coders::{Encoder,Decoder};
use rustc_serialize::Decodable;
use rustc_serialize::Encodable;

use super::block::Block;

const ENTRY_SIZE             : u32 = 4;
const SUB_BUCKET_HEADER_SIZE : u32 = 1024;
 // header size 1024 bytes / entry size 4 bytes
const MAX_SUB_BUCKETS        : u32 = SUB_BUCKET_HEADER_SIZE / ENTRY_SIZE;
const MAX_DATA_SIZE          : u32 = 4096 - SUB_BUCKET_HEADER_SIZE - super::HASH_FOOTER_SIZE - super::block::BLOCK_FOOTER_SIZE;

static CANT_GROW_ERR : &'static str = "We can't grow in this implementation so indexes past 256 are untenable";

#[derive(Copy, Clone)]
pub struct Entry {
    offset: u16,
    size: u16,
}

pub fn put_sub_bucket(block : &mut Block, index : u32, map : &HashMap<i32,i32>) -> Result<(), String> {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let buf : Vec<u8>;
    match encode_msgpack(map) {
        Ok(v)  => buf = v,
        Err(e) => return Err(e),
    }

    let size       = buf.len() as u16;
    let mut entry  = get_entry(&block, index);

    // Hard case - it doesn't fit, allocate new
    if size > entry.size {
        match find_space(&block, size) {
            Some(off) => entry.offset = off,
            None      => return Err("Ran out of disk space I guess".to_string()),
        }
    }

    entry.size = size;
    put_entry(block, index, entry);
    for (i, b) in buf.iter().enumerate() {
        block[i+(entry.offset as usize)] = *b;
    }

    Ok(())
}

pub fn del_sub_bucket(block : &mut Block, index : u32) {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    put_entry(block, index, Entry { offset: 0, size: 0 });
}

pub fn get_sub_bucket(block : &Block, index : u32) -> Result<Option<HashMap<i32,i32>>, String> {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let entry = get_entry(block, index);
    if entry.size == 0 {
        return Ok(None)
    }

    let offset = entry.offset as usize;
    let size = entry.size as usize;

    match decode_msgpack(&block[offset..offset+size]) {
        Ok(v)  => Ok(Some(v)),
        Err(e) => return Err(e),
    }
}

/// Put an entry to some index, panics on bad index
fn put_entry(block : &mut Block, index : u32, e : Entry) {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let i = (index * 4) as usize;
    let j = i + 2;

    BigEndian::write_u16(&mut block[i..i+2], e.offset);
    BigEndian::write_u16(&mut block[j..j+2], e.size);
}

/// Get an entry from an index, panics on bad index
fn get_entry(block : &Block, index : u32) -> Entry {
    if index >= MAX_SUB_BUCKETS {
        panic!(CANT_GROW_ERR)
    }

    let i = (index * 4) as usize;
    let j = i + 2;

    Entry {
        offset: BigEndian::read_u16(&block[i..i+2]),
        size: BigEndian::read_u16(&block[j..j+2]),
    }
}

/// Find a offset in memory for our data length, or None
fn find_space(block : &Block, want_size : u16) -> Option<u16> {
    let mut next_offset = SUB_BUCKET_HEADER_SIZE as u16;
    let size = next_power_of_2(want_size);

    // Sort all the entries such that they're ordered by offset
    let mut entries : Vec<Entry> = BlockIterator::new(&block).collect();
    entries.sort();

    for e in entries {
        if e.size == 0 {
            continue;
        }

        if next_offset + size <= e.offset {
            break;
        }

        next_offset = e.offset + next_power_of_2(e.size);
    }

    if next_offset + size > MAX_DATA_SIZE as u16 {
        return None;
    }

    Some(next_offset)
}

/// Return a buffer with the serialized hash map in it.
fn encode_msgpack(map : &HashMap<i32,i32>) -> Result<Vec<u8>, String> {
    let mut buf: Vec<u8> = Vec::new();

    {
        let mut encoder = Encoder::new(&mut buf);
        if let Some(e) = map.encode(&mut encoder).err() {
            return Err(format!("error writing map: {}", e))
        }
    }

    Ok(buf)
}

/// Decode a serialized hash map from a slice
fn decode_msgpack(slice : &[u8]) -> Result<HashMap<i32,i32>, String> {
    let c = Cursor::new(slice);

    let mut decoder = Decoder::new(c);
    match Decodable::decode(&mut decoder) {
        Ok(h)  => return Ok(h),
        Err(e) => Err(format!("error reading map: {}", e)),
    }
}

/// Bit twiddling magic function.
///
/// Essentially continuously or's it with itself
/// moving bits down the row and once all the bits
/// are filled in it adds one to turn on the next
/// power of two bit.
fn next_power_of_2(from : u16) -> u16 {
    let mut n = from - 1;
    n |= n >> 1;
    n |= n >> 2;
    n |= n >> 4;
    n |= n >> 8;
    //n |= n >> 16; // Not needed since I've shrank the size of the integer
    n + 1
}

struct BlockIterator<'a> {
    i: u32,
    block: &'a [ u8; 4096 ],
}

impl<'a> BlockIterator<'a> {
    fn new(b : &Block) -> BlockIterator {
        BlockIterator {
            i: 0,
            block: b,
        }
    }
}

impl<'a> Iterator for BlockIterator<'a> {
    type Item = Entry;

    fn next(&mut self) -> Option<Entry> {
        if self.i == 256 {
            return None
        }

        let entry = get_entry(self.block, self.i);
        self.i += 1;

        return Some(entry);
    }
}

// This chunk of code is pretty ridiculous. Haskell beats you here pretty hard Rust.
impl PartialOrd for Entry {
    fn partial_cmp(&self, other : &Entry) -> Option<Ordering> { self.offset.partial_cmp(&other.offset) }
}
impl PartialEq for Entry {
    fn eq(&self, other : &Entry) -> bool { self.offset.eq(&other.offset) }
}
impl Ord for Entry {
    fn cmp(&self, other : &Entry) -> Ordering { self.offset.cmp(&other.offset) }
}
impl Eq for Entry {}

#[cfg(test)]
mod tests {
    use std::collections::HashMap;

    use super::super::block::*;

    #[test]
    fn get_put_sub_bucket() {
        let mut b : Block = new_block!();

        let mut h = HashMap::new();
        h.insert(5, 6);
        h.insert(7, 8);

        super::put_sub_bucket(&mut b, 1, &h).unwrap();

        let h2 = super::get_sub_bucket(&b, 1).unwrap().unwrap();
        assert_eq!(h, h2);

        let h3 = super::get_sub_bucket(&b, 2).unwrap();
        assert!(h3.is_none());
    }

    #[test]
    fn del_sub_bucket() {
        let mut b : Block = new_block!();

        let mut h = HashMap::new();
        h.insert(5, 6);
        h.insert(7, 8);

        super::put_sub_bucket(&mut b, 0, &mut h).unwrap();
        super::del_sub_bucket(&mut b, 0);
        let h = super::get_sub_bucket(&mut b, 0).unwrap();
        assert!(h.is_none());
    }

    #[test]
    fn get_entry() {
        let mut b : Block = new_block!();

        // write an entry at b[40] of size: 257, offset: 258
        b[40] = 1;
        b[41] = 1;
        b[42] = 1;
        b[43] = 2;

        let entry = super::get_entry(&b, 10);

        assert_eq!(entry.offset, 257);
        assert_eq!(entry.size, 258);
    }

    #[test]
    fn put_entry() {
        let mut b : Block = new_block!();
        let e = super::Entry { size: 257, offset: 258 };

        super::put_entry(&mut b, 10, e);

        let entry = super::get_entry(&b, 10);

        assert_eq!(entry.size, 257);
        assert_eq!(entry.offset, 258);
    }

    #[test]
    fn find_space() {
        let mut b : Block = new_block!();

        // If the entire space is taken error
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: super::MAX_DATA_SIZE as u16 });
        assert_eq!(super::find_space(&b, 9), None);
    }

    #[test]
    fn find_space_end() {
        let mut b : Block = new_block!();

        // If there's space at the end
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: 9 });
        super::put_entry(&mut b, 2, super::Entry { offset: 16, size: 25 });

        assert_eq!(super::find_space(&b, 28).unwrap(), 48);
    }

    #[test]
    fn find_space_middle() {
        let mut b : Block = new_block!();

        // If there's a chunk in between somewhere (out of order)
        super::put_entry(&mut b, 0, super::Entry { offset: 0, size: 9 });
        super::put_entry(&mut b, 1, super::Entry { offset: 64, size: 26 });
        super::put_entry(&mut b, 2, super::Entry { offset: 16, size: 25 });

        assert_eq!(super::find_space(&b, 9).unwrap(), 48);
        assert_eq!(super::find_space(&b, 28).unwrap(), 96);
    }

    #[test]
    fn next_power_of_2() {
        assert_eq!(super::next_power_of_2(1), 1);
        assert_eq!(super::next_power_of_2(3), 4);
        assert_eq!(super::next_power_of_2(5), 8);
        assert_eq!(super::next_power_of_2(6), 8);
        assert_eq!(super::next_power_of_2(11), 16);
        assert_eq!(super::next_power_of_2(17), 32);
    }

    #[test]
    fn iterators() {
        let b : Block = new_block!();
        let mut bi = super::BlockIterator::new(&b);

        let mut count = 0;
        for e in bi {
            count += 1;
        }

        bi = super::BlockIterator::new(&b);
        bi.collect::<Vec<super::Entry>>().sort();

        assert_eq!(count, super::MAX_SUB_BUCKETS);
    }

    #[test]
    fn sorting() {
        let mut b : Block = new_block!();

        super::put_entry(&mut b, 0, super::Entry { offset: 196, size: 16 });
        super::put_entry(&mut b, 1, super::Entry { offset: 16, size: 32 });
        super::put_entry(&mut b, 2, super::Entry { offset: 36, size: 32 });

        let mut entries : Vec<super::Entry> = super::BlockIterator::new(&b).collect();
        entries.sort();

        let offsets : Vec<u16> = entries.iter().map(|i| i.offset).collect();

        // There's going to be a lot of zeroes in here, cull them out
        assert_eq!(offsets[offsets.len()-3..], [16, 36, 196]);
    }
}
<|endoftext|>


<commit_before>use crate::{Change, CrateVersion, Index};
use git_repository as git;
use git_repository::refs::transaction::PreviousValue;
use std::convert::TryFrom;

static LINE_ADDED_INDICATOR: char = '+';

/// The error returned by methods dealing with obtaining index changes.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
    #[error(transparent)]
    Fetch(#[from] git2::Error),
    #[error(transparent)]
    ReferenceEdit(#[from] git::reference::edit::Error),
    #[error(transparent)]
    RevParse(#[from] git::revision::spec::parse::Error),
}

/// Find changes without modifying the underling repository
impl Index {
    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        self.peek_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        let repo = &self.repo;
        let from = repo
            .find_reference(self.seen_ref_name)
            .ok()
            .and_then(|r| r.try_id().map(|id| id.detach()))
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        let to = {
            let repo = git2::Repository::open(repo.git_dir())?;
            repo.find_remote("origin").and_then(|mut r| {
                r.fetch(
                    &[format!(
                        "refs/heads/{branch}:refs/remotes/origin/{branch}",
                        branch = self.branch_name
                    )],
                    options,
                    None,
                )
            })?;
            git::hash::ObjectId::try_from(
                repo.refname_to_id(&format!("refs/remotes/origin/{}", self.branch_name))?
                    .as_bytes(),
            )
            .expect("valid oid")
        };

        Ok((self.changes_between_commits(from, to)?, to))
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_between_commits(
        &self,
        from: impl Into<git::hash::ObjectId>,
        to: impl Into<git::hash::ObjectId>,
    ) -> Result<Vec<Change>, Error> {
        let repo = git2::Repository::open(self.repo.git_dir())?;
        let from = git2::Oid::from_bytes(from.into().as_slice())?;
        let to = git2::Oid::from_bytes(to.into().as_slice())?;
        fn into_tree<'a>(
            repo: &'a git2::Repository,
            obj: &git2::Object<'_>,
        ) -> Result<git2::Tree<'a>, git2::Error> {
            repo.find_tree(match obj.kind() {
                Some(git2::ObjectType::Commit) => obj
                    .as_commit()
                    .expect("object of kind commit yields commit")
                    .tree_id(),
                _ =>
                /* let it possibly fail later */
                {
                    obj.id()
                }
            })
        }
        let from = repo.find_object(from, None)?;
        let to = repo.find_object(to, None)?;
        let diff = repo.diff_tree_to_tree(
            Some(&into_tree(&repo, &from)?),
            Some(&into_tree(&repo, &to)?),
            None,
        )?;
        let mut changes: Vec<Change> = Vec::new();
        let mut deletes: Vec<String> = Vec::new();
        diff.foreach(
            &mut |delta, _| {
                if delta.status() == git2::Delta::Deleted {
                    if let Some(path) = delta.new_file().path() {
                        if let Some(file_name) = path.file_name() {
                            deletes.push(file_name.to_string_lossy().to_string());
                        }
                    }
                }
                true
            },
            None,
            None,
            Some(&mut |delta, _hunk, diffline| {
                if diffline.origin() != LINE_ADDED_INDICATOR {
                    return true;
                }
                if !matches!(delta.status(), git2::Delta::Added | git2::Delta::Modified) {
                    return true;
                }

                if let Ok(crate_version) =
                    serde_json::from_slice::<CrateVersion>(diffline.content())
                {
                    if crate_version.yanked {
                        changes.push(Change::Yanked(crate_version));
                    } else {
                        changes.push(Change::Added(crate_version));
                    }
                }
                true
            }),
        )?;

        changes.extend(deletes.iter().map(|krate| Change::Deleted(krate.clone())));
        Ok(changes)
    }
}

/// Find changes while changing the underlying repository in one way or another.
impl Index {
    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<Change>, Error> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<Change>, Error> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: git::hash::ObjectId) -> Result<(), Error> {
        let repo = self.repository();
        repo.reference(
            self.seen_ref_name,
            to,
            PreviousValue::Any,
            "updating seen-ref head to latest fetched commit",
        )?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<Change>, Error> {
        let repo = self.repository();
        let from = repo
            .rev_parse(from.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        let to = repo
            .rev_parse(to.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        self.changes_between_commits(from, to)
    }
}
<commit_msg>frame for diffing (#16)<commit_after>use crate::{Change, CrateVersion, Index};
use git_repository as git;
use git_repository::bstr::BStr;
use git_repository::diff::tree::visit::Action;
use git_repository::prelude::{FindExt, ObjectIdExt, TreeIterExt};
use git_repository::refs::transaction::PreviousValue;
use std::convert::TryFrom;

static LINE_ADDED_INDICATOR: char = '+';

/// The error returned by methods dealing with obtaining index changes.
#[derive(Debug, thiserror::Error)]
#[allow(missing_docs)]
pub enum Error {
    #[error(transparent)]
    Fetch(#[from] git2::Error),
    #[error(transparent)]
    ReferenceEdit(#[from] git::reference::edit::Error),
    #[error(transparent)]
    RevParse(#[from] git::revision::spec::parse::Error),
    #[error(transparent)]
    FindObject(#[from] git::object::find::existing::Error),
    #[error(transparent)]
    PeelToTree(#[from] git::object::peel::to_kind::Error),
    #[error(transparent)]
    Diff(#[from] git::diff::tree::changes::Error),
}

/// Find changes without modifying the underling repository
impl Index {
    /// As `peek_changes_with_options`, but without the options.
    pub fn peek_changes(&self) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        self.peek_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time `fetch_changes(…)` was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will not be created or updated.
    /// The second field in the returned tuple is the commit object to which the changes were provided.
    /// If one would set the `last_seen_reference()` to that object, the effect is exactly the same
    /// as if `fetch_changes(…)` had been called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn peek_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<(Vec<Change>, git::hash::ObjectId), Error> {
        let repo = &self.repo;
        let from = repo
            .find_reference(self.seen_ref_name)
            .ok()
            .and_then(|r| r.try_id().map(|id| id.detach()))
            .unwrap_or_else(|| git::hash::ObjectId::empty_tree(repo.object_hash()));
        let to = {
            let repo = git2::Repository::open(repo.git_dir())?;
            repo.find_remote("origin").and_then(|mut r| {
                r.fetch(
                    &[format!(
                        "refs/heads/{branch}:refs/remotes/origin/{branch}",
                        branch = self.branch_name
                    )],
                    options,
                    None,
                )
            })?;
            git::hash::ObjectId::try_from(
                repo.refname_to_id(&format!("refs/remotes/origin/{}", self.branch_name))?
                    .as_bytes(),
            )
            .expect("valid oid")
        };

        Ok((self.changes_between_commits(from, to)?, to))
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_between_commits(
        &self,
        from: impl Into<git::hash::ObjectId>,
        to: impl Into<git::hash::ObjectId>,
    ) -> Result<Vec<Change>, Error> {
        let repo = git2::Repository::open(self.repo.git_dir())?;
        let from = git2::Oid::from_bytes(from.into().as_slice())?;
        let to = git2::Oid::from_bytes(to.into().as_slice())?;
        fn into_tree<'a>(
            repo: &'a git2::Repository,
            obj: &git2::Object<'_>,
        ) -> Result<git2::Tree<'a>, git2::Error> {
            repo.find_tree(match obj.kind() {
                Some(git2::ObjectType::Commit) => obj
                    .as_commit()
                    .expect("object of kind commit yields commit")
                    .tree_id(),
                _ =>
                /* let it possibly fail later */
                {
                    obj.id()
                }
            })
        }
        let from = repo.find_object(from, None)?;
        let to = repo.find_object(to, None)?;
        let diff = repo.diff_tree_to_tree(
            Some(&into_tree(&repo, &from)?),
            Some(&into_tree(&repo, &to)?),
            None,
        )?;
        let mut changes: Vec<Change> = Vec::new();
        let mut deletes: Vec<String> = Vec::new();
        diff.foreach(
            &mut |delta, _| {
                if delta.status() == git2::Delta::Deleted {
                    if let Some(path) = delta.new_file().path() {
                        if let Some(file_name) = path.file_name() {
                            deletes.push(file_name.to_string_lossy().to_string());
                        }
                    }
                }
                true
            },
            None,
            None,
            Some(&mut |delta, _hunk, diffline| {
                if diffline.origin() != LINE_ADDED_INDICATOR {
                    return true;
                }
                if !matches!(delta.status(), git2::Delta::Added | git2::Delta::Modified) {
                    return true;
                }

                if let Ok(crate_version) =
                    serde_json::from_slice::<CrateVersion>(diffline.content())
                {
                    if crate_version.yanked {
                        changes.push(Change::Yanked(crate_version));
                    } else {
                        changes.push(Change::Added(crate_version));
                    }
                }
                true
            }),
        )?;

        changes.extend(deletes.iter().map(|krate| Change::Deleted(krate.clone())));
        Ok(changes)
    }

    /// Similar to `changes()`, but requires `from` and `to` objects to be provided. They may point
    /// to either `Commit`s or `Tree`s.
    pub fn changes_between_commits2(
        &mut self,
        from: impl Into<git::hash::ObjectId>,
        to: impl Into<git::hash::ObjectId>,
    ) -> Result<Vec<Change>, Error> {
        let changes = Vec::new();
        self.repo.object_cache_size_if_unset(4 * 1024 * 1024);
        let into_tree = |id: git::hash::ObjectId| -> Result<git::Tree<'_>, Error> {
            Ok(id
                .attach(&self.repo)
                .object()?
                .peel_to_kind(git::object::Kind::Tree)?
                .into_tree())
        };
        let from = into_tree(from.into())?;
        let to = into_tree(to.into())?;
        struct Delegate;
        impl git::diff::tree::Visit for Delegate {
            fn pop_front_tracked_path_and_set_current(&mut self) {
                todo!()
            }

            fn push_back_tracked_path_component(&mut self, _component: &BStr) {
                todo!()
            }

            fn push_path_component(&mut self, _component: &BStr) {
                todo!()
            }

            fn pop_path_component(&mut self) {
                todo!()
            }

            fn visit(&mut self, _change: git::diff::tree::visit::Change) -> Action {
                todo!()
            }
        }
        git::objs::TreeRefIter::from_bytes(&from.data).changes_needed(
            git::objs::TreeRefIter::from_bytes(&to.data),
            git::diff::tree::State::default(),
            |id, buf| self.repo.objects.find_tree_iter(id, buf).ok(),
            &mut Delegate,
        )?;

        Ok(changes)
    }
}

/// Find changes while changing the underlying repository in one way or another.
impl Index {
    /// As `fetch_changes_with_options`, but without the options.
    pub fn fetch_changes(&self) -> Result<Vec<Change>, Error> {
        self.fetch_changes_with_options(None)
    }

    /// Return all `Change`s that are observed between the last time this method was called
    /// and the latest state of the `crates.io` index repository, which is obtained by fetching
    /// the remote called `origin`.
    /// The `last_seen_reference()` will be created or adjusted to point to the latest fetched
    /// state, which causes this method to have a different result each time it is called.
    ///
    /// # Resource Usage
    ///
    /// As this method fetches the git repository, loose objects or small packs may be created. Over time,
    /// these will accumulate and either slow down subsequent operations, or cause them to fail due to exhaustion
    /// of the maximum number of open file handles as configured with `ulimit`.
    ///
    /// Thus it is advised for the caller to run `git gc` occasionally based on their own requirements and usage patterns.
    pub fn fetch_changes_with_options(
        &self,
        options: Option<&mut git2::FetchOptions<'_>>,
    ) -> Result<Vec<Change>, Error> {
        let (changes, to) = self.peek_changes_with_options(options)?;
        self.set_last_seen_reference(to)?;
        Ok(changes)
    }

    /// Set the last seen reference to the given Oid. It will be created if it does not yet exists.
    pub fn set_last_seen_reference(&self, to: git::hash::ObjectId) -> Result<(), Error> {
        let repo = self.repository();
        repo.reference(
            self.seen_ref_name,
            to,
            PreviousValue::Any,
            "updating seen-ref head to latest fetched commit",
        )?;
        Ok(())
    }

    /// Return all `CreateVersion`s observed between `from` and `to`. Both parameter are ref-specs
    /// pointing to either a commit or a tree.
    /// Learn more about specifying revisions
    /// in the
    /// [official documentation](https://www.kernel.org/pub/software/scm/git/docs/gitrevisions.html)
    pub fn changes(
        &self,
        from: impl AsRef<str>,
        to: impl AsRef<str>,
    ) -> Result<Vec<Change>, Error> {
        let repo = self.repository();
        let from = repo
            .rev_parse(from.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        let to = repo
            .rev_parse(to.as_ref())?
            .single()
            .expect("revspec was not a range")
            .detach();
        self.changes_between_commits(from, to)
    }
}
<|endoftext|>


<commit_before>//! Define traits wrapping LAPACK routines

pub mod cholesky;
pub mod eigh;
pub mod opnorm;
pub mod qr;
pub mod solve;
pub mod solveh;
pub mod svd;
pub mod triangular;

pub use self::cholesky::*;
pub use self::eigh::*;
pub use self::opnorm::*;
pub use self::qr::*;
pub use self::solve::*;
pub use self::solveh::*;
pub use self::svd::*;
pub use self::triangular::*;

use super::error::*;
use super::types::*;

pub type Pivot = Vec<i32>;

pub trait Lapack: OperatorNorm_ + QR_ + SVD_ + Solve_ + Solveh_ + Cholesky_ + Eigh_ + Triangular_ {}

impl Lapack for f32 {}
impl Lapack for f64 {}
impl Lapack for c32 {}
impl Lapack for c64 {}

pub fn into_result<T>(return_code: i32, val: T) -> Result<T> {
    if return_code == 0 {
        Ok(val)
    } else {
        Err(LinalgError::Lapack { return_code })
    }
}

/// Upper/Lower specification for seveal usages
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum UPLO {
    Upper = b'U',
    Lower = b'L',
}

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Transpose {
    No = b'N',
    Transpose = b'T',
    Hermite = b'C',
}

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum NormType {
    One = b'O',
    Infinity = b'I',
    Frobenius = b'F',
}

impl NormType {
    pub(crate) fn transpose(self) -> Self {
        match self {
            NormType::One => NormType::Infinity,
            NormType::Infinity => NormType::One,
            NormType::Frobenius => NormType::Frobenius,
        }
    }
}
<commit_msg>Add short doc of Lapack trait<commit_after>//! Define traits wrapping LAPACK routines

pub mod cholesky;
pub mod eigh;
pub mod opnorm;
pub mod qr;
pub mod solve;
pub mod solveh;
pub mod svd;
pub mod triangular;

pub use self::cholesky::*;
pub use self::eigh::*;
pub use self::opnorm::*;
pub use self::qr::*;
pub use self::solve::*;
pub use self::solveh::*;
pub use self::svd::*;
pub use self::triangular::*;

use super::error::*;
use super::types::*;

pub type Pivot = Vec<i32>;

/// Trait for primitive types which implements LAPACK subroutines
pub trait Lapack: OperatorNorm_ + QR_ + SVD_ + Solve_ + Solveh_ + Cholesky_ + Eigh_ + Triangular_ {}

impl Lapack for f32 {}
impl Lapack for f64 {}
impl Lapack for c32 {}
impl Lapack for c64 {}

pub fn into_result<T>(return_code: i32, val: T) -> Result<T> {
    if return_code == 0 {
        Ok(val)
    } else {
        Err(LinalgError::Lapack { return_code })
    }
}

/// Upper/Lower specification for seveal usages
#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum UPLO {
    Upper = b'U',
    Lower = b'L',
}

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum Transpose {
    No = b'N',
    Transpose = b'T',
    Hermite = b'C',
}

#[derive(Debug, Clone, Copy)]
#[repr(u8)]
pub enum NormType {
    One = b'O',
    Infinity = b'I',
    Frobenius = b'F',
}

impl NormType {
    pub(crate) fn transpose(self) -> Self {
        match self {
            NormType::One => NormType::Infinity,
            NormType::Infinity => NormType::One,
            NormType::Frobenius => NormType::Frobenius,
        }
    }
}
<|endoftext|>


<commit_before>use crate::{
    core_arch::{simd::*, simd_llvm::*, x86::*},
    mem::{self, transmute},
};

#[cfg(test)]
use stdarch_test::assert_instr;

/// Computes the absolute values of packed 32-bit integers in `a`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33&text=_mm512_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_abs_epi32(a: __m512i) -> __m512i {
    let a = a.as_i32x16();
    // all-0 is a properly initialized i32x16
    let zero: i32x16 = mem::zeroed();
    let sub = simd_sub(zero, a);
    let cmp: i32x16 = simd_gt(a, zero);
    transmute(simd_select(cmp, a, sub))
}

/// Computes the absolute value of packed 32-bit integers in `a`, and store the
/// unsigned results in `dst` using writemask `k` (elements are copied from
/// `src` when the corresponding mask bit is not set).
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33&text=_mm512_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_mask_abs_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i {
    let abs = _mm512_abs_epi32(a).as_i32x16();
    transmute(simd_select_bitmask(k, abs, src.as_i32x16()))
}

/// Computes the absolute value of packed 32-bit integers in `a`, and store the
/// unsigned results in `dst` using zeromask `k` (elements are zeroed out when
/// the corresponding mask bit is not set).
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33,34,35,35&text=_mm512_maskz_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_maskz_abs_epi32(k: __mmask16, a: __m512i) -> __m512i {
    let abs = _mm512_abs_epi32(a).as_i32x16();
    let zero = _mm512_setzero_si512().as_i32x16();
    transmute(simd_select_bitmask(k, abs, zero))
}

/// Returns vector of type `__m512i` with all elements set to zero.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vxorps))]
pub unsafe fn _mm512_setzero_si512() -> __m512i {
    // All-0 is a properly initialized __m512i
    mem::zeroed()
}

/// Sets packed 32-bit integers in `dst` with the supplied values in reverse
/// order.
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_setr_epi32(
    e15: i32,
    e14: i32,
    e13: i32,
    e12: i32,
    e11: i32,
    e10: i32,
    e9: i32,
    e8: i32,
    e7: i32,
    e6: i32,
    e5: i32,
    e4: i32,
    e3: i32,
    e2: i32,
    e1: i32,
    e0: i32,
) -> __m512i {
    let r = i32x16(
        e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0,
    );
    transmute(r)
}

/// Broadcast 64-bit integer `a` to all elements of `dst`.
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i {
    transmute(i64x8::splat(a))
}

/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu64)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpcmpltuq))]
pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 {
    simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8()))
}

#[cfg(test)]
mod tests {
    use std;
    use stdarch_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_abs_epi32(a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
        );
        assert_eq_m512i(r, e);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_mask_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_mask_abs_epi32(a, 0, a);
        assert_eq_m512i(r, a);
        let r = _mm512_mask_abs_epi32(a, 0b11111111, a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            1,
            -1,
            i32::MAX,
            i32::MIN,
            100,
            -100,
            -32,
        );
        assert_eq_m512i(r, e);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_maskz_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_maskz_abs_epi32(0, a);
        assert_eq_m512i(r, _mm512_setzero_si512());
        let r = _mm512_maskz_abs_epi32(0b11111111, a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        );
        assert_eq_m512i(r, e);
    }
}
<commit_msg>Only check for the instruction prefix since MSVC and Clang use different instructions<commit_after>use crate::{
    core_arch::{simd::*, simd_llvm::*, x86::*},
    mem::{self, transmute},
};

#[cfg(test)]
use stdarch_test::assert_instr;

/// Computes the absolute values of packed 32-bit integers in `a`.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33&text=_mm512_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_abs_epi32(a: __m512i) -> __m512i {
    let a = a.as_i32x16();
    // all-0 is a properly initialized i32x16
    let zero: i32x16 = mem::zeroed();
    let sub = simd_sub(zero, a);
    let cmp: i32x16 = simd_gt(a, zero);
    transmute(simd_select(cmp, a, sub))
}

/// Computes the absolute value of packed 32-bit integers in `a`, and store the
/// unsigned results in `dst` using writemask `k` (elements are copied from
/// `src` when the corresponding mask bit is not set).
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33&text=_mm512_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_mask_abs_epi32(src: __m512i, k: __mmask16, a: __m512i) -> __m512i {
    let abs = _mm512_abs_epi32(a).as_i32x16();
    transmute(simd_select_bitmask(k, abs, src.as_i32x16()))
}

/// Computes the absolute value of packed 32-bit integers in `a`, and store the
/// unsigned results in `dst` using zeromask `k` (elements are zeroed out when
/// the corresponding mask bit is not set).
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990,33,34,35,35&text=_mm512_maskz_abs_epi32)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpabsd))]
pub unsafe fn _mm512_maskz_abs_epi32(k: __mmask16, a: __m512i) -> __m512i {
    let abs = _mm512_abs_epi32(a).as_i32x16();
    let zero = _mm512_setzero_si512().as_i32x16();
    transmute(simd_select_bitmask(k, abs, zero))
}

/// Returns vector of type `__m512i` with all elements set to zero.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_si512)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vxorps))]
pub unsafe fn _mm512_setzero_si512() -> __m512i {
    // All-0 is a properly initialized __m512i
    mem::zeroed()
}

/// Sets packed 32-bit integers in `dst` with the supplied values in reverse
/// order.
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_setr_epi32(
    e15: i32,
    e14: i32,
    e13: i32,
    e12: i32,
    e11: i32,
    e10: i32,
    e9: i32,
    e8: i32,
    e7: i32,
    e6: i32,
    e5: i32,
    e4: i32,
    e3: i32,
    e2: i32,
    e1: i32,
    e0: i32,
) -> __m512i {
    let r = i32x16(
        e15, e14, e13, e12, e11, e10, e9, e8, e7, e6, e5, e4, e3, e2, e1, e0,
    );
    transmute(r)
}

/// Broadcast 64-bit integer `a` to all elements of `dst`.
#[inline]
#[target_feature(enable = "avx512f")]
pub unsafe fn _mm512_set1_epi64(a: i64) -> __m512i {
    transmute(i64x8::splat(a))
}

/// Compare packed unsigned 64-bit integers in a and b for less-than, and store the results in a mask vector.
///
/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062&text=_mm512_cmplt_epu64)
#[inline]
#[target_feature(enable = "avx512f")]
#[cfg_attr(test, assert_instr(vpcmp))]
pub unsafe fn _mm512_cmplt_epu64_mask(a: __m512i, b: __m512i) -> __mmask8 {
    simd_bitmask::<__m512i, _>(simd_lt(a.as_u64x8(), b.as_u64x8()))
}

#[cfg(test)]
mod tests {
    use std;
    use stdarch_test::simd_test;

    use crate::core_arch::x86::*;

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_abs_epi32(a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
        );
        assert_eq_m512i(r, e);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_mask_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_mask_abs_epi32(a, 0, a);
        assert_eq_m512i(r, a);
        let r = _mm512_mask_abs_epi32(a, 0b11111111, a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            1,
            -1,
            i32::MAX,
            i32::MIN,
            100,
            -100,
            -32,
        );
        assert_eq_m512i(r, e);
    }

    #[simd_test(enable = "avx512f")]
    unsafe fn test_mm512_maskz_abs_epi32() {
        #[rustfmt::skip]
        let a = _mm512_setr_epi32(
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
            0, 1, -1, i32::MAX,
            i32::MIN, 100, -100, -32,
        );
        let r = _mm512_maskz_abs_epi32(0, a);
        assert_eq_m512i(r, _mm512_setzero_si512());
        let r = _mm512_maskz_abs_epi32(0b11111111, a);
        let e = _mm512_setr_epi32(
            0,
            1,
            1,
            i32::MAX,
            i32::MAX.wrapping_add(1),
            100,
            100,
            32,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
            0,
        );
        assert_eq_m512i(r, e);
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

pub mod ll;
<commit_msg>Add BlasMatrix trait<commit_after>// Copyright 2014 Michael Yang. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.

use attribute::{
    Order,
    RowMajor,
    Transpose,
    NoTrans,
};

pub mod ll;

pub trait BlasMatrix<T> {
    fn lead_dim(&self) -> i32 { self.rows() }
    fn order(&self) -> Order { RowMajor }
    fn transpose(&self) -> Transpose { NoTrans }
    fn rows(&self) -> i32;
    fn cols(&self) -> i32;
    fn as_ptr(&self) -> *const T;
    fn as_mut_ptr(&mut self) -> *mut T;
}

pub trait BandMatrix<T>: BlasMatrix<T> {
    fn sub_diagonals(&self) -> i32;
    fn sup_diagonals(&self) -> i32;
}
<|endoftext|>


<commit_before>use super::{allocate_state, Mesh};
use crate::shapes::Shape;
use crate::StrError;

/// Checks if the IDs of points and cells are sequential
///
/// This function checks that:
///
/// * the index of a point in the points vector matches the id of the point
/// * the index of a cell in the cells vector matches the id of the cell
pub fn check_ids(mesh: &Mesh) -> Result<(), StrError> {
    for i in 0..mesh.points.len() {
        if mesh.points[i].id != i {
            return Err("invalid point id found; ids must be sequential");
        }
    }
    for i in 0..mesh.cells.len() {
        if mesh.cells[i].id != i {
            return Err("invalid cell id found; ids must be sequential");
        }
    }
    Ok(())
}

/// Checks if the determinant of the Jacobian of all cells are non-negative
pub fn check_jacobian(mesh: &Mesh) -> Result<(), StrError> {
    let ksi = [0.0, 0.0, 0.0];
    for cell in &mesh.cells {
        let shape = Shape::new(mesh.space_ndim, cell.geo_ndim, cell.points.len())?;
        let mut state = allocate_state(mesh, cell.geo_ndim, &cell.points)?;
        let det_jac = shape.calc_jacobian(&mut state, &ksi)?;
        if det_jac < 0.0 {
            return Err("negative determinant of Jacobian found");
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{check_ids, check_jacobian};
    use crate::mesh::{Cell, Mesh, Point};

    #[test]
    fn check_ids_works() {
        //  3-----------2-----------5
        //  |           |           |
        //  |    [0]    |    [1]    |
        //  |    (1)    |    (2)    |
        //  |           |           |
        //  0-----------1-----------4
        #[rustfmt::skip]
        let mut mesh = Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        };
        assert_eq!(check_ids(&mesh).expect("should not fail"), ());

        mesh.points[0].id = 6;
        assert_eq!(
            check_ids(&mesh).err(),
            Some("invalid point id found; ids must be sequential")
        );
        mesh.points[0].id = 0;

        assert_eq!(check_ids(&mesh).expect("should not fail"), ());

        mesh.cells[0].id = 2;
        assert_eq!(
            check_ids(&mesh).err(),
            Some("invalid cell id found; ids must be sequential")
        );
        mesh.cells[0].id = 0;
    }

    #[test]
    fn check_jacobian_works() {
        //  3-----------2-----------5
        //  |           |           |
        //  |    [0]    |    [1]    |
        //  |    (1)    |    (2)    |
        //  |           |           |
        //  0-----------1-----------4
        #[rustfmt::skip]
        let mut mesh = Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        };
        assert_eq!(check_jacobian(&mesh).expect("should not fail"), ());

        mesh.cells[0].points[2] = 3;
        mesh.cells[0].points[3] = 2;
        assert_eq!(
            check_jacobian(&mesh).err(),
            Some("cannot compute inverse due to zero determinant")
        );

        mesh.cells[0].points = vec![0, 3, 2, 1];
        assert_eq!(
            check_jacobian(&mesh).err(),
            Some("negative determinant of Jacobian found")
        );
    }
}
<commit_msg>Impl check edges normals<commit_after>use super::{allocate_state, Edge, EdgeKey, Mesh};
use crate::shapes::Shape;
use crate::StrError;
use russell_lab::Vector;
use std::collections::HashMap;

/// Checks if the IDs of points and cells are sequential
///
/// This function checks that:
///
/// * the index of a point in the points vector matches the id of the point
/// * the index of a cell in the cells vector matches the id of the cell
pub fn check_ids(mesh: &Mesh) -> Result<(), StrError> {
    for i in 0..mesh.points.len() {
        if mesh.points[i].id != i {
            return Err("invalid point id found; ids must be sequential");
        }
    }
    for i in 0..mesh.cells.len() {
        if mesh.cells[i].id != i {
            return Err("invalid cell id found; ids must be sequential");
        }
    }
    Ok(())
}

/// Checks if the determinant of the Jacobian of all cells are non-negative
pub fn check_jacobian(mesh: &Mesh) -> Result<(), StrError> {
    let ksi = [0.0, 0.0, 0.0];
    for cell in &mesh.cells {
        let shape = Shape::new(mesh.space_ndim, cell.geo_ndim, cell.points.len())?;
        let mut state = allocate_state(mesh, cell.geo_ndim, &cell.points)?;
        let det_jac = shape.calc_jacobian(&mut state, &ksi)?;
        if det_jac < 0.0 {
            return Err("negative determinant of Jacobian found");
        }
    }
    Ok(())
}

/// Checks if normal vectors of some edges are correct
pub fn check_2d_edge_normals(
    mesh: &Mesh,
    edges: &HashMap<EdgeKey, Edge>,
    solutions: &HashMap<EdgeKey, [f64; 2]>,
    tolerance: f64,
) -> Result<(), StrError> {
    const GEO_NDIM: usize = 1;
    let ksi = &[0.0, 0.0];
    let mut normal = Vector::new(mesh.space_ndim);
    for (edge_key, solution) in solutions {
        let edge = edges.get(edge_key).ok_or("cannot find edge_key in edges map")?;
        let shape = Shape::new(mesh.space_ndim, GEO_NDIM, edge.points.len())?;
        let mut state = allocate_state(mesh, GEO_NDIM, &edge.points)?;
        shape.calc_boundary_normal(&mut normal, &mut state, ksi)?;
        for i in 0..mesh.space_ndim {
            if f64::abs(normal[i] - solution[i]) > tolerance {
                return Err("wrong normal vector found");
            }
        }
    }
    Ok(())
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

#[cfg(test)]
mod tests {
    use super::{check_2d_edge_normals, check_ids, check_jacobian};
    use crate::mesh::{Cell, Edge, EdgeKey, Mesh, Point};
    use std::collections::HashMap;

    #[test]
    fn check_ids_works() {
        //  3-----------2-----------5
        //  |           |           |
        //  |    [0]    |    [1]    |
        //  |    (1)    |    (2)    |
        //  |           |           |
        //  0-----------1-----------4
        #[rustfmt::skip]
        let mut mesh = Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        };
        assert_eq!(check_ids(&mesh).expect("should not fail"), ());

        mesh.points[0].id = 6;
        assert_eq!(
            check_ids(&mesh).err(),
            Some("invalid point id found; ids must be sequential")
        );
        mesh.points[0].id = 0;

        assert_eq!(check_ids(&mesh).expect("should not fail"), ());

        mesh.cells[0].id = 2;
        assert_eq!(
            check_ids(&mesh).err(),
            Some("invalid cell id found; ids must be sequential")
        );
        mesh.cells[0].id = 0;
    }

    #[test]
    fn check_jacobian_works() {
        //  3-----------2-----------5
        //  |           |           |
        //  |    [0]    |    [1]    |
        //  |    (1)    |    (2)    |
        //  |           |           |
        //  0-----------1-----------4
        #[rustfmt::skip]
        let mut mesh = Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        };
        assert_eq!(check_jacobian(&mesh).expect("should not fail"), ());

        mesh.cells[0].points[2] = 3;
        mesh.cells[0].points[3] = 2;
        assert_eq!(
            check_jacobian(&mesh).err(),
            Some("cannot compute inverse due to zero determinant")
        );

        mesh.cells[0].points = vec![0, 3, 2, 1];
        assert_eq!(
            check_jacobian(&mesh).err(),
            Some("negative determinant of Jacobian found")
        );
    }

    #[test]
    fn check_2d_edge_normals_works() {
        //
        //             ^         ^
        //             |         |
        //             |         |
        //        3-------->2-------->5
        //        ^         |         |
        // <===== |   [0]   |   [1]   | =====>
        //        |         |         V
        //        0<--------1<--------4
        //             |         |
        //             |         |
        //             V         V
        //
        #[rustfmt::skip]
        let mesh = Mesh {
            space_ndim: 2,
            points: vec![
                Point { id: 0, coords: vec![0.0, 0.0] },
                Point { id: 1, coords: vec![1.0, 0.0] },
                Point { id: 2, coords: vec![1.0, 1.0] },
                Point { id: 3, coords: vec![0.0, 1.0] },
                Point { id: 4, coords: vec![2.0, 0.0] },
                Point { id: 5, coords: vec![2.0, 1.0] },
            ],
            cells: vec![
                Cell { id: 0, attribute_id: 1, geo_ndim: 2, points: vec![0, 1, 2, 3] },
                Cell { id: 1, attribute_id: 2, geo_ndim: 2, points: vec![1, 4, 5, 2] },
            ],
        };

        // the magnitude (l) of the normal vector should be equal to
        // 0.5 = edge_length / 2.0 where 2.0 corresponds to the edge_length in the reference system
        let l = 0.5; // magnitude of normal vector

        let mut edges: HashMap<EdgeKey, Edge> = HashMap::from([
            ((0, 3), Edge { points: vec![0, 3] }),
            ((2, 3), Edge { points: vec![3, 2] }),
            ((2, 5), Edge { points: vec![2, 5] }),
            ((4, 5), Edge { points: vec![5, 4] }),
            ((1, 4), Edge { points: vec![4, 1] }),
            ((0, 1), Edge { points: vec![1, 0] }),
        ]);
        let solutions: HashMap<EdgeKey, [f64; 2]> = HashMap::from([
            ((0, 3), [-l, 0.0]),
            ((2, 3), [0.0, l]),
            ((2, 5), [0.0, l]),
            ((4, 5), [l, 0.0]),
            ((1, 4), [0.0, -l]),
            ((0, 1), [0.0, -l]),
        ]);
        assert_eq!(check_2d_edge_normals(&mesh, &edges, &solutions, 1e-15).expect("ok"), ());

        let points = &mut edges.get_mut(&(0, 3)).unwrap().points;
        points[0] = 3;
        points[1] = 0;
        assert_eq!(
            check_2d_edge_normals(&mesh, &edges, &solutions, 1e-15).err(),
            Some("wrong normal vector found")
        );

        let solutions: HashMap<EdgeKey, [f64; 2]> = HashMap::from([((10, 20), [0.0, l])]);
        assert_eq!(
            check_2d_edge_normals(&mesh, &edges, &solutions, 1e-15).err(),
            Some("cannot find edge_key in edges map")
        );
    }
}
<|endoftext|>


<commit_before>use mime::{Mime, TopLevel, SubLevel};

use serialize::json;

use std::cell::RefCell;

use std::collections::HashMap;

/// Guess the MIME type of the `Path` by its extension.
///
/// **Guess** is the operative word here, as the contents of a file
/// may not or may not match its MIME type/extension.
pub fn guess_mime_type(path: &Path) -> Mime {
    let ext = path.extension_str().unwrap_or("");

    get_mime_type(ext)
}

pub fn guess_mime_type_filename(filename: &str) -> Mime {
    let path = Path::new(filename);

    guess_mime_type(&path)
}

local_data_key!(mime_types_cache: RefCell<HashMap<String, Mime>>)

/// Get the MIME type associated with a file extension
// MIME Types are cached in a task-local heap
pub fn get_mime_type(ext: &str) -> Mime {
    if ext.is_empty() { return octet_stream(); }

    let ext = ext.into_string();

    let cache = if let Some(cache) = mime_types_cache.get() { cache }
    else {
        mime_types_cache.replace(Some(RefCell::new(HashMap::new())));
        mime_types_cache.get().unwrap()
    };

    if let Some(mime_type) = cache.borrow().get(&ext) {
        return mime_type.clone();
    }

    let mime_type = find_mime_type(&*ext);

    cache.borrow_mut().insert(ext, mime_type.clone());

    mime_type
}

const MIME_TYPES: &'static str = include_str!("../mime_types.json");

/// Load the MIME_TYPES as JSON and try to locate `ext`
fn find_mime_type(ext: &str) -> Mime {
    json::from_str(MIME_TYPES).unwrap()
        .find(ext).and_then(|j| j.as_string())
        .and_then(from_str::<Mime>)
        .unwrap_or_else(octet_stream)
}

pub fn octet_stream() -> Mime {
    Mime(TopLevel::Application, SubLevel::Ext("octet-stream".into_string()), Vec::new())
}

#[test]
fn test_mime_type_guessing() {
    assert!(get_mime_type("gif").to_string() == "image/gif".to_string());
    assert!(get_mime_type("txt").to_string() == "text/plain".to_string());
    assert!(get_mime_type("blahblah").to_string() == "application/octet-stream".to_string());
}

<commit_msg>Update mime_guess.rs<commit_after>use mime::{Mime, TopLevel, SubLevel};

use serialize::json;

use std::cell::RefCell;

use std::collections::HashMap;

/// Guess the MIME type of the `Path` by its extension.
///
/// **Guess** is the operative word here, as the contents of a file
/// may not or may not match its MIME type/extension.
pub fn guess_mime_type(path: &Path) -> Mime {
    let ext = path.extension_str().unwrap_or("");

    get_mime_type(ext)
}

pub fn guess_mime_type_filename(filename: &str) -> Mime {
    let path = Path::new(filename);

    guess_mime_type(&path)
}

local_data_key!(mime_types_cache: RefCell<HashMap<String, Mime>>)

/// Get the MIME type associated with a file extension
pub fn get_mime_type(ext: &str) -> Mime {
    if ext.is_empty() { return octet_stream(); }

    let ext = ext.into_string();

    // MIME Types are cached in a task-local heap
    let cache = if let Some(cache) = mime_types_cache.get() { cache }
    else {
        mime_types_cache.replace(Some(RefCell::new(HashMap::new())));
        mime_types_cache.get().unwrap()
    };

    if let Some(mime_type) = cache.borrow().get(&ext) {
        return mime_type.clone();
    }

    let mime_type = find_mime_type(&*ext);

    cache.borrow_mut().insert(ext, mime_type.clone());

    mime_type
}

const MIME_TYPES: &'static str = include_str!("../mime_types.json");

/// Load the MIME_TYPES as JSON and try to locate `ext`
fn find_mime_type(ext: &str) -> Mime {
    json::from_str(MIME_TYPES).unwrap()
        .find(ext).and_then(|j| j.as_string())
        .and_then(from_str::<Mime>)
        .unwrap_or_else(octet_stream)
}

/// Get the `Mime` type for `application/octet-stream` (generic binary stream)
pub fn octet_stream() -> Mime {
    Mime(TopLevel::Application, SubLevel::Ext("octet-stream".into_string()), Vec::new())
}

#[test]
fn test_mime_type_guessing() {
    assert!(get_mime_type("gif").to_string() == "image/gif".to_string());
    assert!(get_mime_type("txt").to_string() == "text/plain".to_string());
    assert!(get_mime_type("blahblah").to_string() == "application/octet-stream".to_string());
}

<|endoftext|>


<commit_before>use std::result;
use super::BOARD_WIDTH;
use super::BOARD_HEIGHT;

pub type Result<T> = result::Result<T, String>;

const MOVEMENT_SPEED: f64 = 1.0;

pub static TETROMINOS: [Tetromino; 7] = [
    Tetromino {
        name: Shape::I,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.0, 1.0, 1.0, 1.0]
    },
    Tetromino {
        name: Shape::J,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.0, 1.0, 1.0, 1.0]
    },
    Tetromino {
        name: Shape::L,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [1.0, 0.6, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::O,
        blocks: [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 1.0,
        y_offset: 0.0,
        color: [1.0, 1.0, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::S,
        blocks: [[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.48, 1.0, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::T,
        blocks: [[0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.4, 0.0, 0.8, 1.0]
    },
    Tetromino {
        name: Shape::Z,
        blocks: [[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [1.0, 0.0, 0.0, 1.0]
    },
];

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Shape {
    I,
    O,
    T,
    S,
    Z,
    J,
    L
}

#[derive(Debug, Clone, Copy)]
pub struct Tetromino {
    pub name: Shape,
    pub blocks: [[u8; 4]; 4],
    pub x_offset: f64, // offset (in block cell units) of the top left cell
    pub y_offset: f64,
    pub color: [f32; 4] // color of the block
}

impl Tetromino {
    pub fn rotate_right(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[4 - c - 1][r];
            }
        }
        self.blocks = new_blocks;
    }

    pub fn rotate_left(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[c][4 - r - 1];
            }
        }

        self.blocks = new_blocks;
    }

    pub fn block_height(&self) -> f64 {
        let mut height = 0.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    height += 1.0;
                    break;
                }
            }
        }
        height
    }

    pub fn block_width(&self) -> f64 {
        let mut cols_vec: [i64; 4] = [0, 0, 0, 0];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    cols_vec[c] = 1;
                }
            }
        }
        let mut width = 0.0;
        for x in cols_vec.iter() {
            if *x == 1 {
                width += 1.0;
            }
        }
        width
    }

    // coordinates of leftmost point in block
    pub fn leftmost(&self) -> f64 {
        let mut leftmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if leftmost > c as f64 {
                        leftmost = c as f64;
                    }
                }
            }
        }
        leftmost + self.x_offset
    }

    pub fn rightmost(&self) -> f64 {
        self.leftmost() + self.block_width() - 1.0
    }

    pub fn topmost(&self) -> f64 {
        let mut topmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if topmost > r as f64 {
                        topmost = r as f64;
                    }
                }
            }
        }
        topmost + self.y_offset
    }

    pub fn bottommost(&self) -> f64 {
        self.topmost() + self.block_height() - 1.0
    }

    pub fn move_down(&mut self) {
        self.y_offset += MOVEMENT_SPEED;
    }

    pub fn move_left(&mut self) {
        self.x_offset -= MOVEMENT_SPEED;
    }

    pub fn move_right(&mut self) {
        self.x_offset += MOVEMENT_SPEED;
    }
}<commit_msg>change J block color to blue<commit_after>use std::result;
use super::BOARD_WIDTH;
use super::BOARD_HEIGHT;

pub type Result<T> = result::Result<T, String>;

const MOVEMENT_SPEED: f64 = 1.0;

pub static TETROMINOS: [Tetromino; 7] = [
    Tetromino {
        name: Shape::I,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.0, 1.0, 1.0, 1.0]
    },
    Tetromino {
        name: Shape::J,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.11, 0.56, 1.0, 1.0]
    },
    Tetromino {
        name: Shape::L,
        blocks: [[0, 1, 0, 0], [0, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [1.0, 0.6, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::O,
        blocks: [[1, 1, 0, 0], [1, 1, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 1.0,
        y_offset: 0.0,
        color: [1.0, 1.0, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::S,
        blocks: [[0, 0, 0, 0], [0, 1, 1, 0], [1, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.48, 1.0, 0.0, 1.0]
    },
    Tetromino {
        name: Shape::T,
        blocks: [[0, 0, 0, 0], [1, 1, 1, 0], [0, 1, 0, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [0.4, 0.0, 0.8, 1.0]
    },
    Tetromino {
        name: Shape::Z,
        blocks: [[0, 0, 0, 0], [1, 1, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0]],
        x_offset: (BOARD_WIDTH as f64 / 2.0) - 2.0,
        y_offset: 0.0,
        color: [1.0, 0.0, 0.0, 1.0]
    },
];

#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Shape {
    I,
    O,
    T,
    S,
    Z,
    J,
    L
}

#[derive(Debug, Clone, Copy)]
pub struct Tetromino {
    pub name: Shape,
    pub blocks: [[u8; 4]; 4],
    pub x_offset: f64, // offset (in block cell units) of the top left cell
    pub y_offset: f64,
    pub color: [f32; 4] // color of the block
}

impl Tetromino {
    pub fn rotate_right(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[4 - c - 1][r];
            }
        }
        self.blocks = new_blocks;
    }

    pub fn rotate_left(&mut self) {
        if self.name == Shape::O {
            return
        }
        let mut new_blocks = [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]];

        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                new_blocks[r][c] = self.blocks[c][4 - r - 1];
            }
        }

        self.blocks = new_blocks;
    }

    pub fn block_height(&self) -> f64 {
        let mut height = 0.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    height += 1.0;
                    break;
                }
            }
        }
        height
    }

    pub fn block_width(&self) -> f64 {
        let mut cols_vec: [i64; 4] = [0, 0, 0, 0];
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    cols_vec[c] = 1;
                }
            }
        }
        let mut width = 0.0;
        for x in cols_vec.iter() {
            if *x == 1 {
                width += 1.0;
            }
        }
        width
    }

    // coordinates of leftmost point in block
    pub fn leftmost(&self) -> f64 {
        let mut leftmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if leftmost > c as f64 {
                        leftmost = c as f64;
                    }
                }
            }
        }
        leftmost + self.x_offset
    }

    pub fn rightmost(&self) -> f64 {
        self.leftmost() + self.block_width() - 1.0
    }

    pub fn topmost(&self) -> f64 {
        let mut topmost = 3.0;
        for (r, row) in self.blocks.iter().enumerate() {
            for (c, col) in row.iter().enumerate() {
                if self.blocks[r][c] == 1 {
                    if topmost > r as f64 {
                        topmost = r as f64;
                    }
                }
            }
        }
        topmost + self.y_offset
    }

    pub fn bottommost(&self) -> f64 {
        self.topmost() + self.block_height() - 1.0
    }

    pub fn move_down(&mut self) {
        self.y_offset += MOVEMENT_SPEED;
    }

    pub fn move_left(&mut self) {
        self.x_offset -= MOVEMENT_SPEED;
    }

    pub fn move_right(&mut self) {
        self.x_offset += MOVEMENT_SPEED;
    }
}<|endoftext|>


<commit_before>use super::*;

/// New vec is bigger than old vec.
fn grow_merkle_cache(old_bytes: &[u8], old_flags: &[bool], to: usize) -> Option<Vec<u8>> {
    let mut bytes = Vec::with_capacity(to * HASHSIZE);
    let mut flags = Vec::with_capacity(to);

    let from = old_bytes.len() / HASHSIZE;
    let to = to;

    let distance = (from.leading_zeros() - to.leading_zeros()) as usize;

    let leading_zero_chunks = 1 >> distance;

    bytes.resize(leading_zero_chunks * HASHSIZE, 0);
    flags.resize(leading_zero_chunks, true); // all new chunks are modified by default.

    for i in 0..to.leading_zeros() as usize {
        let new_slice = bytes.get_mut(1 >> i + distance..1 >> i + distance + 1)?;
        let old_slice = old_bytes.get(1 >> i..1 >> i + 1)?;
        new_slice.copy_from_slice(old_slice);
    }

    Some(bytes)
}

#[cfg(test)]
mod test {
    #[test]
    fn can_grow() {
        // TODO
    }
}
<commit_msg>Refactor resize functions for clarity<commit_after>use super::*;

/// New vec is bigger than old vec.
fn grow_merkle_cache(
    old_bytes: &[u8],
    old_flags: &[bool],
    from_height: usize,
    to_height: usize,
) -> Option<Vec<u8>> {
    let to_nodes = (1 << to_height.next_power_of_two()) - 1;

    // Determine the size of our new tree. It is not just a simple `1 << to_height` as there can be
    // an arbitrary number of bytes in `old_bytes` leaves.
    let new_byte_count = {
        let additional_from_nodes = old_bytes.len() / HASHSIZE - ((1 << from_height) - 1);
        ((1 << to_height + additional_from_nodes) - 1) * HASHSIZE
    };
    dbg!(new_byte_count / 32);

    let mut bytes = vec![0; new_byte_count];
    let mut flags = vec![true; to_nodes];

    let leaf_level = from_height - 1;

    // Loop through all internal levels of the tree (skipping the final, leaves level).
    for i in 0..from_height - 1 as usize {
        dbg!(i);
        dbg!(bytes.len());
        // If we're on the leaf slice, grab the first byte and all the of the bytes after that.
        // This is required because we can have an arbitrary number of bytes at the leaf level
        // (e.g., the case where there are subtrees as leaves).
        //
        // If we're not on a leaf level, the number of nodes is fixed and known.
        let old_slice = if i == leaf_level {
            old_bytes.get(first_byte_at_height(i)..)
        } else {
            old_bytes.get(byte_range_at_height(i))
        }?;

        dbg!(byte_range_at_height(i + to_height - from_height));

        let new_slice = bytes
            .get_mut(byte_range_at_height(i + to_height - from_height))?
            .get_mut(0..old_slice.len())?;

        new_slice.copy_from_slice(old_slice);
    }

    Some(bytes)
}

fn byte_range_at_height(h: usize) -> Range<usize> {
    first_byte_at_height(h)..last_node_at_height(h) * HASHSIZE
}

fn first_byte_at_height(h: usize) -> usize {
    first_node_at_height(h) * HASHSIZE
}

fn first_node_at_height(h: usize) -> usize {
    (1 << h) - 1
}

fn last_node_at_height(h: usize) -> usize {
    (1 << (h + 1)) - 1
}

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

    #[test]
    fn can_grow() {
        let from: usize = 7;
        let to: usize = 15;

        let old_bytes = vec![42; from * HASHSIZE];
        let old_flags = vec![false; from];

        let new = grow_merkle_cache(
            &old_bytes,
            &old_flags,
            (from + 1).trailing_zeros() as usize,
            (to + 1).trailing_zeros() as usize,
        )
        .unwrap();

        println!("{:?}", new);
        let mut expected = vec![];
        // First level
        expected.append(&mut vec![0; 32]);
        // Second level
        expected.append(&mut vec![42; 32]);
        expected.append(&mut vec![0; 32]);
        // Third level
        expected.append(&mut vec![42; 32]);
        expected.append(&mut vec![42; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        // Fourth level
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);
        expected.append(&mut vec![0; 32]);

        assert_eq!(expected, new);
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::collections::VecDeque;
use std::collections::hash_map::Keys;
use std::time::Instant;
use config;
use mem;

/// Cache entry
pub struct Entry {
    value: String,
    created: Instant,
    modified: Instant,
}

/// Cache datastore
pub type Data = HashMap<String, Entry>;

#[allow(dead_code)]
pub struct Cache {
    config: config::Config,
    data: Box<Data>,
    keys: Box<VecDeque<String>>,
    bytes: usize
}

impl Cache {
    /// Create new Cache from a cache configuration
    pub fn new(config: config::Config) -> Cache {
        Self {
            config: config,
            data: Box::new(HashMap::new()),
            keys: Box::new(VecDeque::new()),
            bytes: 0,
        }
    }

    /// Empty cache
    pub fn empty(&mut self) {
        self.data.clear();
        self.bytes = 0;
    }

    /// Purge old entries
    pub fn prune(&mut self) {
        let now = Instant::now();
        let mut keys_to_delete: Vec<String> = Vec::new();
        let mut i = 0;

        for key in self.keys.iter() {
            if let Some(entry) = self.data.get(key) {
                let modified_elapsed_secs = now.duration_since(entry.modified).as_secs();

                if modified_elapsed_secs > self.config.cache.ttl {
                    keys_to_delete.push(key.clone());
                }
                else {
                    let created_elapsed_secs = now.duration_since(entry.created).as_secs();
                    if created_elapsed_secs <= self.config.cache.ttl {
                        break;
                    }
                }

                i += 1;
            }
        }

        for key in keys_to_delete.iter() {
            self.delete(key);
        }

        self.keys = Box::new(self.keys.split_off(i));
    }

    /// Get an entry from cache by key
    pub fn get(&mut self, key: &String) -> Option<&String> {
        self.data.get(key).and_then(|e| Some(&e.value))
    }

    /// Insert an entry into cache
    pub fn set(&mut self, key: String, value: String) {
        let now = Instant::now();
        let entry: Entry;

        // Update existing entry at this key
        if let Some(previous_entry) = self.data.get(&key) {
            self.bytes -= mem::get_size_of_string(&previous_entry.value);

            entry = Entry {
                value: value,
                modified: now,
                .. *previous_entry
            };
        }
        // Create a new entry at this key
        else {
            self.bytes += mem::get_size_of_string(&key);

            entry = Entry {
                value: value,
                created: now,
                modified: now,
            };
        }

        self.bytes += mem::get_size_of_string(&entry.value);

        self.data.insert(key.clone(), entry);
        self.keys.push_back(key);
    }

    /// Delete a cache entry
    pub fn delete(&mut self, key: &String) {
        if let Some(entry) = self.data.remove(key) {
            self.bytes -= mem::get_size_of_string(&entry.value) + mem::get_size_of_string(key);
        }
    }

    /// Retrieve all cache entries' keys
    pub fn keys(&self) -> Keys<String, Entry> {
        self.data.keys()
    }

    /// Get number of cache entries
    pub fn count(&self) -> usize {
        self.data.len()
    }

    /// Get approximate size of cache
    pub fn size(&self) -> usize {
        self.bytes
    }
}
<commit_msg>Ensure get never returns stale values<commit_after>use std::collections::HashMap;
use std::collections::VecDeque;
use std::collections::hash_map::Keys;
use std::time::Instant;
use config;
use mem;

/// Cache entry
pub struct Entry {
    value: String,
    created: Instant,
    modified: Instant,
}

/// Cache datastore
pub type Data = HashMap<String, Entry>;

#[allow(dead_code)]
pub struct Cache {
    config: config::Config,
    data: Box<Data>,
    keys: Box<VecDeque<String>>,
    bytes: usize
}

impl Cache {
    /// Create new Cache from a cache configuration
    pub fn new(config: config::Config) -> Cache {
        Self {
            config: config,
            data: Box::new(HashMap::new()),
            keys: Box::new(VecDeque::new()),
            bytes: 0,
        }
    }

    /// Empty cache
    pub fn empty(&mut self) {
        self.data.clear();
        self.bytes = 0;
    }

    /// Purge old entries
    pub fn prune(&mut self) {
        let now = Instant::now();
        let mut keys_to_delete: Vec<String> = Vec::new();
        let mut i = 0;

        for key in self.keys.iter() {
            if let Some(entry) = self.data.get(key) {
                let modified_elapsed_secs = now.duration_since(entry.modified).as_secs();

                if modified_elapsed_secs > self.config.cache.ttl {
                    keys_to_delete.push(key.clone());
                }
                else {
                    let created_elapsed_secs = now.duration_since(entry.created).as_secs();
                    if created_elapsed_secs <= self.config.cache.ttl {
                        break;
                    }
                }

                i += 1;
            }
        }

        for key in keys_to_delete.iter() {
            self.delete(key);
        }

        self.keys = Box::new(self.keys.split_off(i));
    }

    /// Get an entry from cache by key
    pub fn get(&self, key: &String) -> Option<&String> {
        let entry = self.data.get(key);

        if let Some(entry) = entry {
            // Ensure entry isn't stale
            let now = Instant::now();
            let modified_elapsed_secs = now.duration_since(entry.modified).as_secs();

            if modified_elapsed_secs > self.config.cache.ttl {
                return None
            }
        }

        entry.and_then(|e| Some(&e.value))
    }

    /// Insert an entry into cache
    pub fn set(&mut self, key: String, value: String) {
        let now = Instant::now();
        let entry: Entry;

        // Update existing entry at this key
        if let Some(previous_entry) = self.data.get(&key) {
            self.bytes -= mem::get_size_of_string(&previous_entry.value);

            entry = Entry {
                value: value,
                modified: now,
                .. *previous_entry
            };
        }
        // Create a new entry at this key
        else {
            self.bytes += mem::get_size_of_string(&key);

            entry = Entry {
                value: value,
                created: now,
                modified: now,
            };
        }

        self.bytes += mem::get_size_of_string(&entry.value);

        self.data.insert(key.clone(), entry);
        self.keys.push_back(key);
    }

    /// Delete a cache entry
    pub fn delete(&mut self, key: &String) {
        if let Some(entry) = self.data.remove(key) {
            self.bytes -= mem::get_size_of_string(&entry.value) + mem::get_size_of_string(key);
        }
    }

    /// Retrieve all cache entries' keys
    pub fn keys(&self) -> Keys<String, Entry> {
        self.data.keys()
    }

    /// Get number of cache entries
    pub fn count(&self) -> usize {
        self.data.len()
    }

    /// Get approximate size of cache
    pub fn size(&self) -> usize {
        self.bytes
    }
}
<|endoftext|>