<commit_before>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_ELEMENTS_MULTIPLIER: usize = 10;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_elements_list = Vec::new();
            let mut max_elements = LEVEL_M_MAX_ELEMENTS_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_elements *= LEVEL_ELEMENTS_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_elements_list.push(max_elements);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_elements_list, page_sizes);
        }
    };
}

with_levels! {
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    pub level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) {
        key_with_id(&mut key, id);
        self.level_m.insert(&key)
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> bool {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key);
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        m_deleted || levels_deleted
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors: Vec<Box<Cursor>> = vec![box self.level_m.seek(&key, ordering)];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!(
                "upper level have elements {} exceeds {}, start level merging",
                elements, max_elements
            );
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }

    pub fn len(&self) -> usize {
        let mem_len = self.level_m.len();
        let levels_len_sum = self.trees.iter().map(|tree| tree.len()).sum::<usize>();
        return mem_len + levels_len_sum;
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        // TODO: redo this part
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| val.clone())
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| key.clone());
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use byteorder::BigEndian;
    use byteorder::WriteBytesExt;
    use client;
    use futures::prelude::*;
    use rand::distributions::Uniform;
    use rand::thread_rng;
    use rand::Rng;
    use rayon::prelude::*;
    use server::NebServer;
    use server::ServerOptions;
    use std::env;
    use std::io::Cursor as StdCursor;

    fn u64_to_slice(n: u64) -> [u8; 8] {
        let mut key_slice = [0u8; 8];
        {
            let mut cursor = StdCursor::new(&mut key_slice[..]);
            cursor.write_u64::<BigEndian>(n);
        };
        key_slice
    }

    #[test]
    #[ignore]
    pub fn insertions() {
        env_logger::init();
        let server_group = "sstable_index_init";
        let server_addr = String::from("127.0.0.1:5600");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 4 * 1024 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], server_group).unwrap(),
        );
        client.new_schema_with_id(super::get_schema()).wait();
        let tree = LSMTree::new(&client);
        let num = env::var("LSM_TREE_TEST_ITEMS")
            // this value cannot do anything useful to the test
            // must arrange a long-term test to cover every levels
            .unwrap_or("1000".to_string())
            .parse::<u64>()
            .unwrap();

        let tree_clone = tree.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_secs(10));
            let tree_len = tree_clone.len();
            debug!(
                "LSM-Tree now have {}/{} elements, total {:.2}%",
                tree_len,
                num,
                tree_len as f32 / num as f32 * 100.0
            );
        });

        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let key = SmallVec::from_slice(&key_slice);
            tree.insert(key, &id);
        });

        if tree.len() > LEVEL_M_MAX_ELEMENTS_COUNT {
            debug!("Sleep 5 minute for level merge");
            thread::sleep(Duration::from_secs(5 * 60));
        }
        debug!("Dump B+ tree");
        btree::test::dump_tree(&tree.level_m, "lsm_level_m_dump.json");
//        debug!("Start validations");
//        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
//            let mut rng = rand::rngs::OsRng::new().unwrap();
//            let die_range = Uniform::new_inclusive(1, 6);
//            let mut roll_die = rng.sample_iter(&die_range);
//            let i = *i;
//            let id = Id::new(0, i);
//            let key_slice = u64_to_slice(i);
//            let mut key = SmallVec::from_slice(&key_slice);
//            debug!("checking: {}", i);
//            let mut cursor = tree.seek(key.clone(), Ordering::Forward);
//            key_with_id(&mut key, &id);
//            assert_eq!(cursor.current(), Some(&key), "{}", i);
//            if roll_die.next().unwrap() == 6 {
//                for j in i..num {
//                    let id = Id::new(0, j);
//                    let key_slice = u64_to_slice(j);
//                    let mut key = SmallVec::from_slice(&key_slice);
//                    key_with_id(&mut key, &id);
//                    assert_eq!(cursor.current(), Some(&key), "{}/{}", i, j);
//                    assert_eq!(cursor.next(), j != num - 1, "{}/{}", i, j);
//                }
//            }
//        });
    }
}
<commit_msg>cargo fmt<commit_after>use super::btree::{BPlusTree, RTCursor as BPlusTreeCursor};
use super::sstable::*;
use super::*;
use client::AsyncClient;
use itertools::Itertools;
use parking_lot::RwLock;
use ram::segs::MAX_SEGMENT_SIZE;
use std::collections::BTreeSet;
use std::sync::Arc;
use std::thread;
use std::time::Duration;
use std::{mem, ptr};

const LEVEL_M_MAX_ELEMENTS_COUNT: usize = LEVEL_M * LEVEL_M * LEVEL_M;
const LEVEL_ELEMENTS_MULTIPLIER: usize = 10;
const LEVEL_DIFF_MULTIPLIER: usize = 10;
const LEVEL_M: usize = super::btree::NUM_KEYS;
const LEVEL_1: usize = LEVEL_M * LEVEL_DIFF_MULTIPLIER;
const LEVEL_2: usize = LEVEL_1 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_3: usize = LEVEL_2 * LEVEL_DIFF_MULTIPLIER;
const LEVEL_4: usize = LEVEL_3 * LEVEL_DIFF_MULTIPLIER;

type LevelTrees = Vec<Box<SSLevelTree>>;

macro_rules! with_levels {
    ($($sym:ident, $level_size:ident;)*) => {
        $(
            type $sym = [EntryKey; $level_size];
            impl_sspage_slice!($sym, EntryKey, $level_size);
        )*

        fn init_lsm_level_trees(neb_client: &Arc<AsyncClient>) -> (LevelTrees, Vec<usize>, Vec<usize>) {
            let mut trees = LevelTrees::new();
            let mut max_elements_list = Vec::new();
            let mut max_elements = LEVEL_M_MAX_ELEMENTS_COUNT;
            let mut page_sizes = Vec::new();
            $(
                max_elements *= LEVEL_ELEMENTS_MULTIPLIER;
                trees.push(box LevelTree::<$sym>::new(neb_client));
                max_elements_list.push(max_elements);
                page_sizes.push($level_size);
                const_assert!($level_size * KEY_SIZE <= MAX_SEGMENT_SIZE);
            )*
            return (trees, max_elements_list, page_sizes);
        }
    };
}

with_levels! {
    L1, LEVEL_1;
    L2, LEVEL_2;
    L3, LEVEL_3;
    L4, LEVEL_4;
}

pub struct LSMTree {
    pub level_m: BPlusTree,
    trees: LevelTrees,
    // use Vec here for convenience
    max_sizes: Vec<usize>,
    page_sizes: Vec<usize>,
}

unsafe impl Send for LSMTree {}
unsafe impl Sync for LSMTree {}

impl LSMTree {
    pub fn new(neb_client: &Arc<AsyncClient>) -> Arc<Self> {
        let (trees, max_sizes, page_sizes) = init_lsm_level_trees(neb_client);
        let lsm_tree = Arc::new(LSMTree {
            level_m: BPlusTree::new(neb_client),
            trees,
            max_sizes,
            page_sizes,
        });
        let tree_clone = lsm_tree.clone();
        thread::spawn(move || {
            tree_clone.sentinel();
        });
        lsm_tree
    }

    pub fn insert(&self, mut key: EntryKey, id: &Id) {
        key_with_id(&mut key, id);
        self.level_m.insert(&key)
    }

    pub fn remove(&self, mut key: EntryKey, id: &Id) -> bool {
        key_with_id(&mut key, id);
        let m_deleted = self.level_m.remove(&key);
        let levels_deleted = self
            .trees
            .iter()
            .map(|tree| tree.mark_deleted(&key))
            .collect_vec() // collect here to prevent short circuit
            .into_iter()
            .any(|d| d);
        m_deleted || levels_deleted
    }

    pub fn seek(&self, mut key: EntryKey, ordering: Ordering) -> LSMTreeCursor {
        match ordering {
            Ordering::Forward => key_with_id(&mut key, &Id::unit_id()),
            Ordering::Backward => key_with_id(&mut key, &Id::new(::std::u64::MAX, ::std::u64::MAX)),
        };
        let mut cursors: Vec<Box<Cursor>> = vec![box self.level_m.seek(&key, ordering)];
        for tree in &self.trees {
            cursors.push(tree.seek(&key, ordering));
        }
        return LSMTreeCursor::new(
            cursors,
            self.trees.iter().map(|t| t.tombstones()).collect_vec(),
        );
    }

    fn sentinel(&self) {
        self.check_and_merge(
            LEVEL_M_MAX_ELEMENTS_COUNT,
            self.page_sizes[0],
            &mut BTreeSet::new(),
            &self.level_m,
            &*self.trees[0],
        );
        for i in 0..self.trees.len() - 1 {
            let upper = &*self.trees[i];
            let lower = &*self.trees[i + 1];
            let upper_tombstons_ref = upper.tombstones();
            let mut upper_tombstones = upper_tombstons_ref.write();
            self.check_and_merge(
                self.max_sizes[i],
                self.page_sizes[i + 1],
                &mut *upper_tombstones,
                upper,
                lower,
            );
        }
        thread::sleep(Duration::from_millis(100));
    }

    fn check_and_merge<U, L>(
        &self,
        max_elements: usize,
        upper_page_size: usize,
        upper_tombstones: &mut TombstonesInner,
        upper_level: &U,
        lower_level: &L,
    ) where
        U: MergeableTree + ?Sized,
        L: SSLevelTree + ?Sized,
    {
        let elements = upper_level.elements();
        if elements > max_elements {
            debug!(
                "upper level have elements {} exceeds {}, start level merging",
                elements, max_elements
            );
            let entries_to_merge = upper_page_size;
            let guard = upper_level.prepare_level_merge();
            let mut pages = vec![guard.last_page()];
            let mut collected_entries = pages.last().unwrap().keys().len();
            while collected_entries < entries_to_merge {
                let next_page = pages.last().unwrap().next();
                collected_entries += next_page.keys().len();
                pages.push(next_page);
            }
            let mut entries = vec![];
            for page in &pages {
                entries.append(&mut Vec::from(page.keys()));
            }
            debug!("going to merge {} entries", entries.len());
            lower_level.merge(entries.as_mut_slice(), upper_tombstones);
            guard.remove_pages(pages.iter().map(|p| p.keys()).collect_vec().as_slice())
        }
    }

    pub fn len(&self) -> usize {
        let mem_len = self.level_m.len();
        let levels_len_sum = self.trees.iter().map(|tree| tree.len()).sum::<usize>();
        return mem_len + levels_len_sum;
    }
}

pub struct LSMTreeCursor {
    level_cursors: Vec<Box<Cursor>>,
    tombstones: Vec<Arc<Tombstones>>,
}

impl LSMTreeCursor {
    fn new(cursors: Vec<Box<Cursor>>, tombstones: Vec<Arc<Tombstones>>) -> Self {
        LSMTreeCursor {
            tombstones,
            level_cursors: cursors,
        }
    }

    fn next_candidate(&mut self) -> (bool, usize) {
        // TODO: redo this part
        let min_tree = self
            .level_cursors
            .iter()
            .enumerate()
            .map(|(i, cursor)| (i, cursor.current()))
            .filter_map(|(i, current)| current.map(|current_val| (i, current_val)))
            .min_by_key(|(i, val)| val.clone())
            .map(|(id, _)| id);
        if let Some(id) = min_tree {
            let min_has_next = self.level_cursors[id].next();
            if !min_has_next {
                let next = self
                    .level_cursors
                    .iter()
                    .enumerate()
                    .filter_map(|(level, cursor)| cursor.current().map(|key| (id, key)))
                    .min_by_key(|(level, key)| key.clone());
                if let Some((id, _)) = next {
                    return (true, id);
                }
            } else {
                return (true, id);
            }
        }
        return (false, 0);
    }
}

impl Cursor for LSMTreeCursor {
    fn next(&mut self) -> bool {
        loop {
            let (has_next, candidate_level) = self.next_candidate();
            if !has_next {
                break;
            }
            if candidate_level == 0 {
                return has_next;
            }
            let candidate_key = self.level_cursors[candidate_level].current().unwrap();
            if self.tombstones[candidate_level + 1]
                .read()
                .contains(candidate_key)
            {
                // marked in tombstone, skip
                continue;
            }
            return true;
        }
        return false;
    }

    fn current(&self) -> Option<&EntryKey> {
        self.level_cursors.iter().filter_map(|c| c.current()).min()
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use byteorder::BigEndian;
    use byteorder::WriteBytesExt;
    use client;
    use futures::prelude::*;
    use rand::distributions::Uniform;
    use rand::thread_rng;
    use rand::Rng;
    use rayon::prelude::*;
    use server::NebServer;
    use server::ServerOptions;
    use std::env;
    use std::io::Cursor as StdCursor;

    fn u64_to_slice(n: u64) -> [u8; 8] {
        let mut key_slice = [0u8; 8];
        {
            let mut cursor = StdCursor::new(&mut key_slice[..]);
            cursor.write_u64::<BigEndian>(n);
        };
        key_slice
    }

    #[test]
    #[ignore]
    pub fn insertions() {
        env_logger::init();
        let server_group = "sstable_index_init";
        let server_addr = String::from("127.0.0.1:5600");
        let server = NebServer::new_from_opts(
            &ServerOptions {
                chunk_count: 1,
                memory_size: 4 * 1024 * 1024 * 1024,
                backup_storage: None,
                wal_storage: None,
            },
            &server_addr,
            &server_group,
        );
        let client = Arc::new(
            client::AsyncClient::new(&server.rpc, &vec![server_addr], server_group).unwrap(),
        );
        client.new_schema_with_id(super::get_schema()).wait();
        let tree = LSMTree::new(&client);
        let num = env::var("LSM_TREE_TEST_ITEMS")
            // this value cannot do anything useful to the test
            // must arrange a long-term test to cover every levels
            .unwrap_or("1000".to_string())
            .parse::<u64>()
            .unwrap();

        let tree_clone = tree.clone();
        thread::spawn(move || {
            thread::sleep(Duration::from_secs(10));
            let tree_len = tree_clone.len();
            debug!(
                "LSM-Tree now have {}/{} elements, total {:.2}%",
                tree_len,
                num,
                tree_len as f32 / num as f32 * 100.0
            );
        });

        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
            let i = *i;
            let id = Id::new(0, i);
            let key_slice = u64_to_slice(i);
            let key = SmallVec::from_slice(&key_slice);
            tree.insert(key, &id);
        });

        if tree.len() > LEVEL_M_MAX_ELEMENTS_COUNT {
            debug!("Sleep 5 minute for level merge");
            thread::sleep(Duration::from_secs(5 * 60));
        }
        debug!("Dump B+ tree");
        btree::test::dump_tree(&tree.level_m, "lsm_level_m_dump.json");
        //        debug!("Start validations");
        //        (0..num).collect::<Vec<_>>().par_iter().for_each(|i| {
        //            let mut rng = rand::rngs::OsRng::new().unwrap();
        //            let die_range = Uniform::new_inclusive(1, 6);
        //            let mut roll_die = rng.sample_iter(&die_range);
        //            let i = *i;
        //            let id = Id::new(0, i);
        //            let key_slice = u64_to_slice(i);
        //            let mut key = SmallVec::from_slice(&key_slice);
        //            debug!("checking: {}", i);
        //            let mut cursor = tree.seek(key.clone(), Ordering::Forward);
        //            key_with_id(&mut key, &id);
        //            assert_eq!(cursor.current(), Some(&key), "{}", i);
        //            if roll_die.next().unwrap() == 6 {
        //                for j in i..num {
        //                    let id = Id::new(0, j);
        //                    let key_slice = u64_to_slice(j);
        //                    let mut key = SmallVec::from_slice(&key_slice);
        //                    key_with_id(&mut key, &id);
        //                    assert_eq!(cursor.current(), Some(&key), "{}/{}", i, j);
        //                    assert_eq!(cursor.next(), j != num - 1, "{}/{}", i, j);
        //                }
        //            }
        //        });
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::fmt::{self, Write};
use std::str;

use http::header::HeaderValue;
use time::{self, Duration};

// "Sun, 06 Nov 1994 08:49:37 GMT".len()
pub const DATE_VALUE_LENGTH: usize = 29;

pub fn extend(dst: &mut Vec<u8>) {
    CACHED.with(|cache| {
        dst.extend_from_slice(cache.borrow().buffer());
    })
}

pub fn update() {
    CACHED.with(|cache| {
        cache.borrow_mut().check();
    })
}

pub(crate) fn update_and_header_value() -> HeaderValue {
    CACHED.with(|cache| {
        let mut cache = cache.borrow_mut();
        cache.check();
        HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
    })
}

struct CachedDate {
    bytes: [u8; DATE_VALUE_LENGTH],
    pos: usize,
    next_update: time::Timespec,
}

thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));

impl CachedDate {
    fn new() -> Self {
        let mut cache = CachedDate {
            bytes: [0; DATE_VALUE_LENGTH],
            pos: 0,
            next_update: time::Timespec::new(0, 0),
        };
        cache.update(time::get_time());
        cache
    }

    fn buffer(&self) -> &[u8] {
        &self.bytes[..]
    }

    fn check(&mut self) {
        let now = time::get_time();
        if now > self.next_update {
            self.update(now);
        }
    }

    fn update(&mut self, now: time::Timespec) {
        self.pos = 0;
        let _ = write!(self, "{}", time::at_utc(now).rfc822());
        debug_assert!(self.pos == DATE_VALUE_LENGTH);
        self.next_update = now + Duration::seconds(1);
        self.next_update.nsec = 0;
    }
}

impl fmt::Write for CachedDate {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let len = s.len();
        self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
        self.pos += len;
        Ok(())
    }
}

#[test]
fn test_date_len() {
    assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
}
<commit_msg>test(h1): add benchmarks for server date checking and rendering<commit_after>use std::cell::RefCell;
use std::fmt::{self, Write};
use std::str;

use http::header::HeaderValue;
use time::{self, Duration};

// "Sun, 06 Nov 1994 08:49:37 GMT".len()
pub const DATE_VALUE_LENGTH: usize = 29;

pub fn extend(dst: &mut Vec<u8>) {
    CACHED.with(|cache| {
        dst.extend_from_slice(cache.borrow().buffer());
    })
}

pub fn update() {
    CACHED.with(|cache| {
        cache.borrow_mut().check();
    })
}

pub(crate) fn update_and_header_value() -> HeaderValue {
    CACHED.with(|cache| {
        let mut cache = cache.borrow_mut();
        cache.check();
        HeaderValue::from_bytes(cache.buffer()).expect("Date format should be valid HeaderValue")
    })
}

struct CachedDate {
    bytes: [u8; DATE_VALUE_LENGTH],
    pos: usize,
    next_update: time::Timespec,
}

thread_local!(static CACHED: RefCell<CachedDate> = RefCell::new(CachedDate::new()));

impl CachedDate {
    fn new() -> Self {
        let mut cache = CachedDate {
            bytes: [0; DATE_VALUE_LENGTH],
            pos: 0,
            next_update: time::Timespec::new(0, 0),
        };
        cache.update(time::get_time());
        cache
    }

    fn buffer(&self) -> &[u8] {
        &self.bytes[..]
    }

    fn check(&mut self) {
        let now = time::get_time();
        if now > self.next_update {
            self.update(now);
        }
    }

    fn update(&mut self, now: time::Timespec) {
        self.render(now);
        self.next_update = now + Duration::seconds(1);
        self.next_update.nsec = 0;
    }

    fn render(&mut self, now: time::Timespec) {
        self.pos = 0;
        let _ = write!(self, "{}", time::at_utc(now).rfc822());
        debug_assert!(self.pos == DATE_VALUE_LENGTH);
    }
}

impl fmt::Write for CachedDate {
    fn write_str(&mut self, s: &str) -> fmt::Result {
        let len = s.len();
        self.bytes[self.pos..self.pos + len].copy_from_slice(s.as_bytes());
        self.pos += len;
        Ok(())
    }
}

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

    #[cfg(feature = "nightly")]
    use test::Bencher;

    #[test]
    fn test_date_len() {
        assert_eq!(DATE_VALUE_LENGTH, "Sun, 06 Nov 1994 08:49:37 GMT".len());
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_date_check(b: &mut Bencher) {
        let mut date = CachedDate::new();
        // cache the first update
        date.check();

        b.iter(|| {
            date.check();
        });
    }

    #[cfg(feature = "nightly")]
    #[bench]
    fn bench_date_render(b: &mut Bencher) {
        let mut date = CachedDate::new();
        let now = time::get_time();
        date.render(now);
        b.bytes = date.buffer().len() as u64;

        b.iter(|| {
            date.render(now);
            test::black_box(&date);
        });
    }
}
<|endoftext|>


<commit_before>mod _common;

use _common::validate;
use std::u64;

fn main() {
    for exp in 19..64 {
        let power: u64 = 1 << exp;
        validate(&power.to_string());
        for offset in 1..123 {
            validate(&(power + offset).to_string());
            validate(&(power - offset).to_string());
        }
    }
    for offset in 0..123 {
        validate(&(u64::MAX - offset).to_string());
    }
}
<commit_msg>Stop importing int module in float parse test<commit_after>mod _common;

use _common::validate;

fn main() {
    for exp in 19..64 {
        let power: u64 = 1 << exp;
        validate(&power.to_string());
        for offset in 1..123 {
            validate(&(power + offset).to_string());
            validate(&(power - offset).to_string());
        }
    }
    for offset in 0..123 {
        validate(&(u64::MAX - offset).to_string());
    }
}
<|endoftext|>


<commit_before>//! This module contains the code representing Mastodon nodes and API Clients
//!
use errors::*;
use futures::{Future, Stream};
use hyper::Client as WebClient;
use hyper::{Body, Uri, Method};
use hyper::Method::{Get, Patch, Post};
use hyper::client::Request;
use hyper::header::{Headers, ContentType, Authorization, Bearer};
use hyper_tls::HttpsConnector;
use mastodon::ApiHandler;
use serde_json;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use super::entities;
use super::methods;
use super::methods::{
    AccountID,
    APIEndpoint,
    APIEndpointRequest,
    HomeTimelineQuery,
    NotificationID,
    RelationshipsQuery,
    SearchAccountsQuery,
    SearchContentsQuery,
    StatusID,
    TagID,
    TimelineQuery,
    UserFormData
};
use tokio_core::reactor::Core;
use url::Url;

/// The API Client, currently works for version 1 of the Mastodon API.
pub struct Client {
    pub url_base: Url,
    pub token: Bearer
}

impl ApiHandler for Client {
    fn endpoint_url(&self, path: &str) -> Result<Url> {
        self.url_base.clone().join(path).chain_err(|| "could not join path with URL")
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).unwrap().into_string()
    }
}

impl APIEndpointRequest for Client {
    fn bearer_token_request(&self, method: Method, uri: Uri) -> Result<Request<Body>> {
        let mut req = Request::new(method, uri);
        req.headers_mut().set(Authorization(self.token.clone()));
        Ok(req)
    }
    fn build_request(&self, endpoint: APIEndpoint) -> Result<Request<Body>> {
        match endpoint {
            APIEndpoint::FetchAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}", account.id));
                let uri = Uri::from_str(&url).unwrap();
                let mut req = Request::new(Get, uri);
                Ok(req)
            },
            APIEndpoint::GetCurrentUser => {
                let url = self.endpoint_url_string("/api/v1/accounts/verify_credentials");
                let uri = Uri::from_str(&url).unwrap();
                let mut req = Request::new(Get, uri);
                Ok(req)
            },
            APIEndpoint::UpdateCurrentUser(d) => {
                let url = self.endpoint_url_string("/api/v1/accounts/update_credentials");
                let uri = Uri::from_str(&url).unwrap();
                let mut req = Request::new(Patch, uri);
                Ok(req)
            },
            APIEndpoint::GetAccountFollowers(a) => {
                let uri = Uri::from_str(&format!("/api/v1/accounts/{}/followers", a.id)).unwrap();
                let mut req = Request::new(Get, uri);
                Ok(req)
            },
            APIEndpoint::GetFollowing(a) => {
                let uri = Uri::from_str(&format!("/api/v1/accounts/{}/following", a.id)).unwrap();
                Ok(Request::new(Get, uri))
            },
            APIEndpoint::GetAccountStatuses(a) => {
                let uri = Uri::from_str(&format!("/api/v1/accounts/{}/statuses", a.id)).unwrap();
                Ok(Request::new(Get, uri))
            },
            APIEndpoint::FollowAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/follow", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnfollowAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/unfollow", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::BlockAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/block", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnblockAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/unblock", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::MuteAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/mute", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnmuteAccount(account) => {
                let url = self.endpoint_url_string(&format!("/api/v1/accounts/{}/unmute", account.id));
                let uri = Uri::from_str(&url).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::GetAccountRelationships(query) => {
                let mut url = self.endpoint_url("/api/v1/accounts/relationships").unwrap();
                match query {
                    RelationshipsQuery::SingleAccount(account) => {
                        url.query_pairs_mut().append_pair("id", &format!("{}", account.id));
                    },
                    RelationshipsQuery::MultipleAccounts(accounts) => {
                        for account in &accounts {
                            url.query_pairs_mut().append_pair("id[]", &format!("{}", account.id));
                        }
                    }
                };
                let req = Request::new(Get, Uri::from_str(url.as_str()).unwrap());
                Ok(req)
            },
            APIEndpoint::SearchAccounts(q) => {
                let mut url = self.endpoint_url("/api/v1/accounts/search").unwrap();
                url.query_pairs_mut().append_pair("q", &q.q);
                if let Some(limit) = q.limit {
                    url.query_pairs_mut().append_pair("limit", &format!("{}", limit));
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Get, uri))
            }
        }
    }

    fn send(&self, endpoint: APIEndpoint, dst: Arc<Mutex<Vec<u8>>>) -> Result<()> {
        let mut core = Core::new().chain_err(|| "Could not start client reactor")?;
        let client = WebClient::configure()
            .connector(HttpsConnector::new(4, &core.handle()))
            .build(&core.handle());

        let req: Request<Body> = self.build_request(endpoint).chain_err(|| "Could not build request")?;
        //req.headers_mut().set(ContentType::form_url_encoded());
        //req.set_body(Body::from(self.form_encode()));

        let mut dst = dst.lock().unwrap();
        let work = client.request(req)
            .and_then(|res| {
                res.body().for_each(|chunk| {
                    dst.extend_from_slice(&chunk);
                    Ok(())
                })
            });
        core.run(work).chain_err(|| "Failed to run registration")?;
        Ok(())
    }
}

impl methods::Accounts for Client {
    fn fetch_account(&self, account_id: AccountID) -> Result<entities::Account> {
        let api_method = APIMethodRequest {
            uri: Uri::from_str(&format!("/api/v1/accounts/{}", account_id.id)).unwrap(),
            ..APIMethodRequest::default()
        };
        println!("FETCH ACCOUNT: {:?}", api_method);
        Ok(entities::Account::default())
    }
    fn get_current_user(&self) -> Result<entities::Account> {
        unimplemented!();
    }
    fn update_current_user(&self, form_data: UserFormData) -> Result<entities::Account> {
        unimplemented!()
    }
    fn get_account_followers(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_following(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_statutes(&self, account_id: AccountID) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn follow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unfollow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn block_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn unblock_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn mute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unmute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn get_account_relationships(&self, query: RelationshipsQuery) -> Result<Vec<entities::Relationship>> {
        unimplemented!()
    }
    fn search_accounts(&self, query: SearchAccountsQuery) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Blocks for Client {
    fn fetch_blocks(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Favourites for Client {
    fn fetch_favourites(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::FollowRequests for Client {
    fn fetch_follow_requests(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn authorize_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
    fn reject_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Follows for Client {
    fn follow_remote_user(&self, form_data: String) -> Result<entities::Account> {
        unimplemented!()
    }
}

impl methods::Instances for Client {
    fn get_instance(&self) -> Result<entities::Instance> {
        unimplemented!()
    }
}

impl methods::Media for Client {
    fn upload_media(&self, form_data: String) -> Result<entities::Attachment> {
        unimplemented!()
    }
}

impl methods::Mutes for Client {
    fn fetch_mutes(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}

impl methods::Notifications for Client {
    fn fetch_notifications(&self, query: String) -> Result<Vec<entities::Notification>> {
        unimplemented!()
    }
    fn get_notification(&self, notification_id: NotificationID) -> Result<entities::Notification> {
        unimplemented!()
    }
    fn clear_notifications(&self) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Reports for Client {
    fn fetching_reports(&self) -> Result<Vec<entities::Report>> {
        unimplemented!()
    }
    fn reporting_user(&self, form_data: String) -> Result<entities::Report> {
        unimplemented!()
    }
}

impl methods::Search for Client {
    fn search_content(&self, query: SearchContentsQuery) -> Result<entities::Results> {
        unimplemented!()
    }
}

impl methods::Statuses for Client {
    fn fetch_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_context(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_card(&self, status_id: StatusID) -> Result<entities::Card> {
        unimplemented!()
    }
    fn reblogged_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn favourited_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn post_status(&self, form_data: String) -> Result<entities::Status> {
        unimplemented!()
    }
    fn delete_status(&self, status_id: StatusID) -> Result<()> {
        unimplemented!()
    }
    fn reblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unreblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn favourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unfavourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
}

impl methods::Timelines for Client {
    fn home_timeline(&self, query: HomeTimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn public_timeline(&self, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn tag_timeline(&self, hashtag: TagID, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
}
<commit_msg>endpoint requests include bearer token<commit_after>//! This module contains the code representing Mastodon nodes and API Clients
//!
use errors::*;
use futures::{Future, Stream};
use hyper::Client as WebClient;
use hyper::{Body, Uri, Method};
use hyper::Method::{Get, Patch, Post};
use hyper::client::Request;
use hyper::header::{Headers, ContentType, Authorization, Bearer};
use hyper_tls::HttpsConnector;
use mastodon::ApiHandler;
use serde_json;
use std::str::FromStr;
use std::sync::{Arc, Mutex};
use super::entities;
use super::methods;
use super::methods::{
    AccountID,
    APIEndpoint,
    APIEndpointRequest,
    HomeTimelineQuery,
    NotificationID,
    RelationshipsQuery,
    SearchAccountsQuery,
    SearchContentsQuery,
    StatusID,
    TagID,
    TimelineQuery,
    UserFormData
};
use tokio_core::reactor::Core;
use url::Url;

/// The API Client, currently works for version 1 of the Mastodon API.
pub struct Client {
    pub url_base: Url,
    pub token: Bearer
}

impl ApiHandler for Client {
    fn endpoint_url(&self, path: &str) -> Result<Url> {
        self.url_base.clone().join(path).chain_err(|| "could not join path with URL")
    }
    fn endpoint_url_string(&self, path: &str) -> String {
        self.endpoint_url(path).unwrap().into_string()
    }
}

impl APIEndpointRequest for Client {
    fn bearer_token_request(&self, method: Method, uri: Uri) -> Result<Request<Body>> {
        let mut req = Request::new(method, uri);
        req.headers_mut().set(Authorization(self.token.clone()));
        Ok(req)
    }
    fn build_request(&self, endpoint: APIEndpoint) -> Result<Request<Body>> {
        match endpoint {
            APIEndpoint::FetchAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetCurrentUser => {
                let url = self.endpoint_url("/api/v1/accounts/verify_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::UpdateCurrentUser(d) => {
                let url = self.endpoint_url("/api/v1/accounts/update_credentials")?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Patch, uri)
            },
            APIEndpoint::GetAccountFollowers(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/followers", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetFollowing(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/following", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::GetAccountStatuses(a) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/statuses", a.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::FollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/follow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnfollowAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unfollow", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::BlockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/block", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::UnblockAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unblock", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                Ok(Request::new(Post, uri))
            },
            APIEndpoint::MuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/mute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::UnmuteAccount(account) => {
                let url = self.endpoint_url(&format!("/api/v1/accounts/{}/unmute", account.id))?;
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Post, uri)
            },
            APIEndpoint::GetAccountRelationships(query) => {
                let mut url = self.endpoint_url("/api/v1/accounts/relationships").unwrap();
                match query {
                    RelationshipsQuery::SingleAccount(account) => {
                        url.query_pairs_mut().append_pair("id", &format!("{}", account.id));
                    },
                    RelationshipsQuery::MultipleAccounts(accounts) => {
                        for account in &accounts {
                            url.query_pairs_mut()
                                .append_pair("id[]", &format!("{}", account.id));
                        }
                    }
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            },
            APIEndpoint::SearchAccounts(q) => {
                let mut url = self.endpoint_url("/api/v1/accounts/search").unwrap();
                url.query_pairs_mut().append_pair("q", &q.q);
                if let Some(limit) = q.limit {
                    url.query_pairs_mut().append_pair("limit", &format!("{}", limit));
                };
                let uri = Uri::from_str(url.as_str()).unwrap();
                self.bearer_token_request(Get, uri)
            }
        }
    }

    fn send(&self, endpoint: APIEndpoint, dst: Arc<Mutex<Vec<u8>>>) -> Result<()> {
        let mut core = Core::new().chain_err(|| "Could not start client reactor")?;
        let client = WebClient::configure()
            .connector(HttpsConnector::new(4, &core.handle()))
            .build(&core.handle());

        let req: Request<Body> = self.build_request(endpoint).chain_err(|| "Could not build request")?;
        //req.headers_mut().set(ContentType::form_url_encoded());
        //req.set_body(Body::from(self.form_encode()));

        let mut dst = dst.lock().unwrap();
        let work = client.request(req)
            .and_then(|res| {
                res.body().for_each(|chunk| {
                    dst.extend_from_slice(&chunk);
                    Ok(())
                })
            });
        core.run(work).chain_err(|| "Failed to run registration")?;
        Ok(())
    }
}

impl methods::Accounts for Client {
    fn fetch_account(&self, account_id: AccountID) -> Result<entities::Account> {
        let api_method = APIMethodRequest {
            uri: Uri::from_str(&format!("/api/v1/accounts/{}", account_id.id)).unwrap(),
            ..APIMethodRequest::default()
        };
        println!("FETCH ACCOUNT: {:?}", api_method);
        Ok(entities::Account::default())
    }
    fn get_current_user(&self) -> Result<entities::Account> {
        unimplemented!();
    }
    fn update_current_user(&self, form_data: UserFormData) -> Result<entities::Account> {
        unimplemented!()
    }
    fn get_account_followers(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_following(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn get_account_statutes(&self, account_id: AccountID) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn follow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unfollow_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn block_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn unblock_account(&self, account_id: AccountID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn mute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn unmute_account(&self, account_id: AccountID) -> Result<entities::Relationship> {
        unimplemented!()
    }
    fn get_account_relationships(&self, query: RelationshipsQuery) -> Result<Vec<entities::Relationship>> {
        unimplemented!()
    }
    fn search_accounts(&self, query: SearchAccountsQuery) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Blocks for Client {
    fn fetch_blocks(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::Favourites for Client {
    fn fetch_favourites(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}
impl methods::FollowRequests for Client {
    fn fetch_follow_requests(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn authorize_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
    fn reject_follow_request(&self, form_data: String) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Follows for Client {
    fn follow_remote_user(&self, form_data: String) -> Result<entities::Account> {
        unimplemented!()
    }
}

impl methods::Instances for Client {
    fn get_instance(&self) -> Result<entities::Instance> {
        unimplemented!()
    }
}

impl methods::Media for Client {
    fn upload_media(&self, form_data: String) -> Result<entities::Attachment> {
        unimplemented!()
    }
}

impl methods::Mutes for Client {
    fn fetch_mutes(&self, query: String) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
}

impl methods::Notifications for Client {
    fn fetch_notifications(&self, query: String) -> Result<Vec<entities::Notification>> {
        unimplemented!()
    }
    fn get_notification(&self, notification_id: NotificationID) -> Result<entities::Notification> {
        unimplemented!()
    }
    fn clear_notifications(&self) -> Result<()> {
        unimplemented!()
    }
}

impl methods::Reports for Client {
    fn fetching_reports(&self) -> Result<Vec<entities::Report>> {
        unimplemented!()
    }
    fn reporting_user(&self, form_data: String) -> Result<entities::Report> {
        unimplemented!()
    }
}

impl methods::Search for Client {
    fn search_content(&self, query: SearchContentsQuery) -> Result<entities::Results> {
        unimplemented!()
    }
}

impl methods::Statuses for Client {
    fn fetch_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_context(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn get_status_card(&self, status_id: StatusID) -> Result<entities::Card> {
        unimplemented!()
    }
    fn reblogged_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn favourited_by(&self, status_id: StatusID) -> Result<Vec<entities::Account>> {
        unimplemented!()
    }
    fn post_status(&self, form_data: String) -> Result<entities::Status> {
        unimplemented!()
    }
    fn delete_status(&self, status_id: StatusID) -> Result<()> {
        unimplemented!()
    }
    fn reblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unreblog_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn favourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
    fn unfavourite_status(&self, status_id: StatusID) -> Result<entities::Status> {
        unimplemented!()
    }
}

impl methods::Timelines for Client {
    fn home_timeline(&self, query: HomeTimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn public_timeline(&self, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
    fn tag_timeline(&self, hashtag: TagID, query: TimelineQuery) -> Result<Vec<entities::Status>> {
        unimplemented!()
    }
}
<|endoftext|>


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

//! Shader parameter handling.

use std::cell::Cell;
use std::rc::Rc;
use std::str;
use s = device::shade;
use device::{RawBufferHandle, ProgramHandle, SamplerHandle, TextureHandle};

/// Helper trait to transform base types into their corresponding uniforms
pub trait ToUniform {
    /// Create a `UniformValue` representing this value.
    fn to_uniform(&self) -> s::UniformValue;
}

macro_rules! impl_ToUniform(
    ($srcty:ty, $dstty:expr) => (
        impl ToUniform for $srcty {
            fn to_uniform(&self) -> s::UniformValue {
                $dstty(*self)
            }
        }
    );
)

impl_ToUniform!(i32, s::ValueI32)
impl_ToUniform!(f32, s::ValueF32)

impl_ToUniform!([i32, ..2], s::ValueI32Vector2)
impl_ToUniform!([i32, ..3], s::ValueI32Vector3)
impl_ToUniform!([i32, ..4], s::ValueI32Vector4)

impl_ToUniform!([f32, ..2], s::ValueF32Vector2)
impl_ToUniform!([f32, ..3], s::ValueF32Vector3)
impl_ToUniform!([f32, ..4], s::ValueF32Vector4)

impl_ToUniform!([[f32, ..2], ..2], s::ValueF32Matrix2)
impl_ToUniform!([[f32, ..3], ..3], s::ValueF32Matrix3)
impl_ToUniform!([[f32, ..4], ..4], s::ValueF32Matrix4)

/// Variable index of a uniform.
pub type VarUniform = u16;

/// Variable index of a uniform block.
pub type VarBlock = u8;

/// Variable index of a texture.
pub type VarTexture = u8;

/// A texture parameter: consists of a texture handle with an optional sampler.
pub type TextureParam = (TextureHandle, Option<SamplerHandle>);

/// A borrowed mutable storage for shader parameter values.
// Not sure if it's the best data structure to represent it.
pub struct ParamValues<'a> {
    /// uniform values to be provided
    pub uniforms: &'a mut [Option<s::UniformValue>],
    /// uniform buffers to be provided
    pub blocks  : &'a mut [Option<RawBufferHandle>],
    /// textures to be provided
    pub textures: &'a mut [Option<TextureParam>],
}

/// Encloses a shader program handle with its parameter
pub trait Program {
    /// Get the contained program handle
    fn get_handle(&self) -> &ProgramHandle;
    /// Get all the contained parameter values
    fn fill_params(&self, ParamValues);
}

impl Program for ProgramHandle {
    fn get_handle(&self) -> &ProgramHandle {
        self
    }

    fn fill_params(&self, params: ParamValues) {
        debug_assert!(
            params.uniforms.is_empty() &&
            params.blocks.is_empty() &&
            params.textures.is_empty(),
            "trying to bind a program that has uniforms ; please call renderer.connect_program first"
        );
    }
}

/// An error type on either the parameter storage or the program side
#[deriving(Clone, PartialEq, Show)]
pub enum ParameterError<'a> {
    /// Internal error
    ErrorInternal,
    /// Error with the named uniform
    ErrorUniform(str::MaybeOwned<'a>),
    /// Error with the named uniform block
    ErrorBlock(str::MaybeOwned<'a>),
    /// Error with the named texture.
    ErrorTexture(str::MaybeOwned<'a>),
}

impl<'a> ParameterError<'a> {
    /// Transform into owned strings to avoid lifetime bounds
    pub fn into_owned(self) -> ParameterError<'static> {
        match self {
            ErrorInternal => ErrorInternal,
            ErrorUniform(s) => ErrorUniform(str::Owned(s.into_string())),
            ErrorBlock(s)   => ErrorBlock(str::Owned(s.into_string())),
            ErrorTexture(s) => ErrorTexture(str::Owned(s.into_string())),
        }
    }
}

/// Abstracts the shader parameter structure, generated by the `shader_param` attribute
pub trait ShaderParam<L> {
    /// Creates a new link, self is passed as a workaround for Rust to not be lost in generics
    fn create_link<'a>(&self, &'a s::ProgramInfo) -> Result<L, ParameterError<'a>>;
    /// Get all the contained parameter values, using a given link.
    fn fill_params(&self, &L, ParamValues);
}

impl ShaderParam<()> for () {
    fn create_link<'a>(&self, info: &'a s::ProgramInfo) -> Result<(), ParameterError<'a>> {
        match info.uniforms.as_slice().head() {
            Some(u) => return Err(ErrorUniform(str::Slice(u.name.as_slice()))),
            None => (),
        }
        match info.blocks.as_slice().head() {
            Some(b) => return Err(ErrorBlock(str::Slice(b.name.as_slice()))),
            None => (),
        }
        match info.textures.as_slice().head() {
            Some(t) => return Err(ErrorTexture(str::Slice(t.name.as_slice()))),
            None => (),
        }
        Ok(())
    }

    fn fill_params(&self, _: &(), _: ParamValues) {
        //empty
    }
}

/// A bundle that encapsulates a program and a custom user-provided
/// structure containing the program parameters.
/// # Type parameters:
///
/// * `L` - auto-generated structure that has a variable index for every field of T
/// * `T` - user-provided structure containing actual parameter values
pub struct UserProgram<L, T> {
    /// Shader program handle
    program: ProgramHandle,
    /// Hidden link that provides parameter indices for user data
    link: L,
    /// Global data in a user-provided struct
    pub data: T,    //TODO: move data out of the shell
}

impl<L: Copy, T: Copy> Clone for UserProgram<L, T> {
    fn clone(&self) -> UserProgram<L, T> {
        UserProgram {
            program: self.program.clone(),
            link: self.link,
            data: self.data,
        }
    }
}

impl<L, T: ShaderParam<L>> UserProgram<L, T> {
    /// Connect a shader program with a parameter structure
    pub fn connect(prog: ProgramHandle, data: T)
                   -> Result<UserProgram<L, T>, ParameterError<'static>> {
        match data.create_link(prog.get_info()) {
            Ok(link) => Ok(UserProgram {
                program: prog.clone(),
                link: link,
                data: data,
            }),
            Err(e) => Err(e.into_owned()),
        }
    }
}

impl<L, T: ShaderParam<L>> Program for UserProgram<L, T> {
    fn get_handle(&self) -> &ProgramHandle {
        &self.program
    }

    fn fill_params(&self, params: ParamValues) {
        self.data.fill_params(&self.link, params);
    }
}

/// A named cell containing arbitrary value
pub struct NamedCell<T> {
    /// Name
    pub name: String,
    /// Value
    pub value: Cell<T>,
}

/// A dictionary of parameters, meant to be shared between different programs
pub struct ParamDictionary {
    /// Uniform dictionary
    pub uniforms: Vec<NamedCell<s::UniformValue>>,
    /// Block dictionary
    pub blocks: Vec<NamedCell<RawBufferHandle>>,
    /// Texture dictionary
    pub textures: Vec<NamedCell<TextureParam>>,
}

/// An associated link structure for `ParamDictionary` that redirects program
/// input to the relevant dictionary cell.
pub struct ParamDictionaryLink {
    uniforms: Vec<uint>,
    blocks: Vec<uint>,
    textures: Vec<uint>,
}

impl<'a> ShaderParam<ParamDictionaryLink> for &'a ParamDictionary {
    fn create_link<'a>(&self, info: &'a s::ProgramInfo)
                   -> Result<ParamDictionaryLink, ParameterError<'a>> {
        //TODO: proper error checks
        Ok(ParamDictionaryLink {
            uniforms: info.uniforms.iter().map(|var|
                self.uniforms.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            blocks: info.blocks.iter().map(|var|
                self.blocks  .iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            textures: info.textures.iter().map(|var|
                self.textures.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
        })
    }

    fn fill_params(&self, link: &ParamDictionaryLink, out: ParamValues) {
        for (&id, var) in link.uniforms.iter().zip(out.uniforms.mut_iter()) {
            *var = Some(self.uniforms[id].value.get());
        }
        for (&id, var) in link.blocks.iter().zip(out.blocks.mut_iter()) {
            *var = Some(self.blocks[id].value.get());
        }
        for (&id, var) in link.textures.iter().zip(out.textures.mut_iter()) {
            *var = Some(self.textures[id].value.get());
        }
    }
}

impl ShaderParam<ParamDictionaryLink> for Rc<ParamDictionary> {
    fn create_link<'a>(&self, info: &'a s::ProgramInfo) ->
                   Result<ParamDictionaryLink, ParameterError<'a>> {
        self.deref().create_link(info)
    }

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

//! Shader parameter handling.

use std::cell::Cell;
use std::rc::Rc;
use std::str;
use s = device::shade;
use device::{RawBufferHandle, ProgramHandle, SamplerHandle, TextureHandle};

/// Helper trait to transform base types into their corresponding uniforms
pub trait ToUniform {
    /// Create a `UniformValue` representing this value.
    fn to_uniform(&self) -> s::UniformValue;
}

macro_rules! impl_ToUniform(
    ($srcty:ty, $dstty:expr) => (
        impl ToUniform for $srcty {
            fn to_uniform(&self) -> s::UniformValue {
                $dstty(*self)
            }
        }
    );
)

impl_ToUniform!(i32, s::ValueI32)
impl_ToUniform!(f32, s::ValueF32)

impl_ToUniform!([i32, ..2], s::ValueI32Vector2)
impl_ToUniform!([i32, ..3], s::ValueI32Vector3)
impl_ToUniform!([i32, ..4], s::ValueI32Vector4)

impl_ToUniform!([f32, ..2], s::ValueF32Vector2)
impl_ToUniform!([f32, ..3], s::ValueF32Vector3)
impl_ToUniform!([f32, ..4], s::ValueF32Vector4)

impl_ToUniform!([[f32, ..2], ..2], s::ValueF32Matrix2)
impl_ToUniform!([[f32, ..3], ..3], s::ValueF32Matrix3)
impl_ToUniform!([[f32, ..4], ..4], s::ValueF32Matrix4)

/// Variable index of a uniform.
pub type VarUniform = u16;

/// Variable index of a uniform block.
pub type VarBlock = u8;

/// Variable index of a texture.
pub type VarTexture = u8;

/// A texture parameter: consists of a texture handle with an optional sampler.
pub type TextureParam = (TextureHandle, Option<SamplerHandle>);

/// A borrowed mutable storage for shader parameter values.
// Not sure if it's the best data structure to represent it.
pub struct ParamValues<'a> {
    /// uniform values to be provided
    pub uniforms: &'a mut [Option<s::UniformValue>],
    /// uniform buffers to be provided
    pub blocks  : &'a mut [Option<RawBufferHandle>],
    /// textures to be provided
    pub textures: &'a mut [Option<TextureParam>],
}

/// Encloses a shader program handle with its parameter
pub trait Program {
    /// Get the contained program handle
    fn get_handle(&self) -> &ProgramHandle;
    /// Get all the contained parameter values
    fn fill_params(&self, ParamValues);
}

impl Program for ProgramHandle {
    fn get_handle(&self) -> &ProgramHandle {
        self
    }

    fn fill_params(&self, params: ParamValues) {
        debug_assert!(
            params.uniforms.is_empty() &&
            params.blocks.is_empty() &&
            params.textures.is_empty(),
            "trying to bind a program handle that has uniforms;\n
            please link with `DeviceHelper::link_program` instead,\n
            or connect with `UserProgram::connect` after construction"
        );
    }
}

/// An error type on either the parameter storage or the program side
#[deriving(Clone, PartialEq, Show)]
pub enum ParameterError<'a> {
    /// Internal error
    ErrorInternal,
    /// Error with the named uniform
    ErrorUniform(str::MaybeOwned<'a>),
    /// Error with the named uniform block
    ErrorBlock(str::MaybeOwned<'a>),
    /// Error with the named texture.
    ErrorTexture(str::MaybeOwned<'a>),
}

impl<'a> ParameterError<'a> {
    /// Transform into owned strings to avoid lifetime bounds
    pub fn into_owned(self) -> ParameterError<'static> {
        match self {
            ErrorInternal => ErrorInternal,
            ErrorUniform(s) => ErrorUniform(str::Owned(s.into_string())),
            ErrorBlock(s)   => ErrorBlock(str::Owned(s.into_string())),
            ErrorTexture(s) => ErrorTexture(str::Owned(s.into_string())),
        }
    }
}

/// Abstracts the shader parameter structure, generated by the `shader_param` attribute
pub trait ShaderParam<L> {
    /// Creates a new link, self is passed as a workaround for Rust to not be lost in generics
    fn create_link<'a>(&self, &'a s::ProgramInfo) -> Result<L, ParameterError<'a>>;
    /// Get all the contained parameter values, using a given link.
    fn fill_params(&self, &L, ParamValues);
}

impl ShaderParam<()> for () {
    fn create_link<'a>(&self, info: &'a s::ProgramInfo) -> Result<(), ParameterError<'a>> {
        match info.uniforms.as_slice().head() {
            Some(u) => return Err(ErrorUniform(str::Slice(u.name.as_slice()))),
            None => (),
        }
        match info.blocks.as_slice().head() {
            Some(b) => return Err(ErrorBlock(str::Slice(b.name.as_slice()))),
            None => (),
        }
        match info.textures.as_slice().head() {
            Some(t) => return Err(ErrorTexture(str::Slice(t.name.as_slice()))),
            None => (),
        }
        Ok(())
    }

    fn fill_params(&self, _: &(), _: ParamValues) {
        //empty
    }
}

/// A bundle that encapsulates a program and a custom user-provided
/// structure containing the program parameters.
/// # Type parameters:
///
/// * `L` - auto-generated structure that has a variable index for every field of T
/// * `T` - user-provided structure containing actual parameter values
pub struct UserProgram<L, T> {
    /// Shader program handle
    program: ProgramHandle,
    /// Hidden link that provides parameter indices for user data
    link: L,
    /// Global data in a user-provided struct
    pub data: T,    //TODO: move data out of the shell
}

impl<L: Copy, T: Copy> Clone for UserProgram<L, T> {
    fn clone(&self) -> UserProgram<L, T> {
        UserProgram {
            program: self.program.clone(),
            link: self.link,
            data: self.data,
        }
    }
}

impl<L, T: ShaderParam<L>> UserProgram<L, T> {
    /// Connect a shader program with a parameter structure
    pub fn connect(prog: ProgramHandle, data: T)
                   -> Result<UserProgram<L, T>, ParameterError<'static>> {
        match data.create_link(prog.get_info()) {
            Ok(link) => Ok(UserProgram {
                program: prog.clone(),
                link: link,
                data: data,
            }),
            Err(e) => Err(e.into_owned()),
        }
    }
}

impl<L, T: ShaderParam<L>> Program for UserProgram<L, T> {
    fn get_handle(&self) -> &ProgramHandle {
        &self.program
    }

    fn fill_params(&self, params: ParamValues) {
        self.data.fill_params(&self.link, params);
    }
}

/// A named cell containing arbitrary value
pub struct NamedCell<T> {
    /// Name
    pub name: String,
    /// Value
    pub value: Cell<T>,
}

/// A dictionary of parameters, meant to be shared between different programs
pub struct ParamDictionary {
    /// Uniform dictionary
    pub uniforms: Vec<NamedCell<s::UniformValue>>,
    /// Block dictionary
    pub blocks: Vec<NamedCell<RawBufferHandle>>,
    /// Texture dictionary
    pub textures: Vec<NamedCell<TextureParam>>,
}

/// An associated link structure for `ParamDictionary` that redirects program
/// input to the relevant dictionary cell.
pub struct ParamDictionaryLink {
    uniforms: Vec<uint>,
    blocks: Vec<uint>,
    textures: Vec<uint>,
}

/// A shader program with dictionary of parameters
pub struct DictionaryProgram {
    program: ProgramHandle,
    link: ParamDictionaryLink,
    data: Rc<ParamDictionary>,
}

impl DictionaryProgram {
    /// Connect a shader program with a parameter structure
    pub fn connect(prog: ProgramHandle, data: Rc<ParamDictionary>)
                   -> Result<DictionaryProgram, ParameterError<'static>> {
        //TODO: proper error checks
        let link = ParamDictionaryLink {
            uniforms: prog.get_info().uniforms.iter().map(|var|
                data.uniforms.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            blocks: prog.get_info().blocks.iter().map(|var|
                data.blocks  .iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
            textures: prog.get_info().textures.iter().map(|var|
                data.textures.iter().position(|c| c.name == var.name).unwrap()
            ).collect(),
        };
        Ok(DictionaryProgram {
            program: prog,
            link: link,
            data: data,
        })
    }
}

impl Program for DictionaryProgram {
    fn get_handle(&self) -> &ProgramHandle {
        &self.program
    }

    fn fill_params(&self, params: ParamValues) {
        for (&id, var) in self.link.uniforms.iter().zip(params.uniforms.mut_iter()) {
            *var = Some(self.data.uniforms[id].value.get());
        }
        for (&id, var) in self.link.blocks.iter().zip(params.blocks.mut_iter()) {
            *var = Some(self.data.blocks[id].value.get());
        }
        for (&id, var) in self.link.textures.iter().zip(params.textures.mut_iter()) {
            *var = Some(self.data.textures[id].value.get());
        }
    }
}
<|endoftext|>


<commit_before>export parmap;

fn parmap<T:send, U:send>(v: [T], f: fn~(T) -> U) -> [U] {
    let futures = vec::map(v) {|elt|
        future::spawn {||
            f(elt)
        }
    };
    vec::map(futures) {|future|
        future::get(future)
    }
}

#[test]
fn test_parallel_map() {
    let i = [1, 2, 3, 4];
    let j = parmap(i) {|e| e + 1 };
    assert j == [2, 3, 4, 5];
}<commit_msg>rustdoc: Do less copying in util::parmap<commit_after>export parmap;

fn parmap<T:send, U:send>(v: [T], f: fn~(T) -> U) -> [U] unsafe {
    let futures = vec::map(v) {|elt|
        let po = comm::port();
        let ch = comm::chan(po);
        let addr = ptr::addr_of(elt);
        task::spawn {||
            comm::send(ch, f(*addr));
        }
        po
    };
    vec::map(futures) {|future|
        comm::recv(future)
    }
}

#[test]
fn test_parallel_map() {
    let i = [1, 2, 3, 4];
    let j = parmap(i) {|e| e + 1 };
    assert j == [2, 3, 4, 5];
}<|endoftext|>


<commit_before>use llvm_sys::prelude::LLVMTypeRef;

use std::fmt::Debug;

use crate::AddressSpace;
use crate::types::{IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VectorType, VoidType, Type};
use crate::types::enums::{AnyTypeEnum, BasicTypeEnum};
use crate::values::{IntMathValue, FloatMathValue, PointerMathValue, IntValue, FloatValue, PointerValue, VectorValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsTypeRef {
    fn as_type_ref(&self) -> LLVMTypeRef;
}

macro_rules! trait_type_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl $trait_name for $args {}
        )*
    );
}

// REVIEW: print_to_string might be a good candidate to live here?
/// Represents any LLVM type.
pub trait AnyType: AsTypeRef + Debug {
    /// Returns an `AnyTypeEnum` that represents the current type.
    fn as_any_type_enum(&self) -> AnyTypeEnum {
        AnyTypeEnum::new(self.as_type_ref())
    }
}

/// Represents a basic LLVM type, that may be used in functions and struct definitions.
pub trait BasicType: AnyType {
    /// Returns a `BasicTypeEnum` that represents the current type.
    fn as_basic_type_enum(&self) -> BasicTypeEnum {
        BasicTypeEnum::new(self.as_type_ref())
    }

    /// Create a function type from this `BasicType`.
    fn fn_type(&self, param_types: &[BasicTypeEnum], is_var_args: bool) -> FunctionType {
        Type::new(self.as_type_ref()).fn_type(param_types, is_var_args)
    }

    /// Create an array type from this `BasicType`.
    fn array_type(&self, size: u32) -> ArrayType {
        Type::new(self.as_type_ref()).array_type(size)
    }

    /// Create a pointer type from this `BasicType`.
    fn ptr_type(&self, address_space: AddressSpace) -> PointerType {
        Type::new(self.as_type_ref()).ptr_type(address_space)
    }
}

/// Represents an LLVM type that can have integer math operations applied to it.
pub trait IntMathType: BasicType {
    /// The value instance of an int or int vector type.
    type ValueType: IntMathValue;
    /// The type for int to float or int vector to float vector conversions.
    type MathConvType: FloatMathType;
    /// The type for int to pointer or int vector to pointer vector conversions.
    type PtrConvType: PointerMathType;
}

/// Represents an LLVM type that can have floating point math operations applied to it.
pub trait FloatMathType: BasicType {
    /// The value instance of a float or float vector type.
    type ValueType: FloatMathValue;
    /// The type for float to int or float vector to int vector conversions.
    type MathConvType: IntMathType;
}

/// Represents an LLVM type that can have pointer operations applied to it.
pub trait PointerMathType: BasicType {
    /// The value instance of a pointer type.
    type ValueType: PointerMathValue;
    /// The type for pointer to int or pointer vector to int conversions.
    type PtrConvType: IntMathType;
}

trait_type_set! {AnyType: AnyTypeEnum, BasicTypeEnum, IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
trait_type_set! {BasicType: BasicTypeEnum, IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl IntMathType for IntType {
    type ValueType = IntValue;
    type MathConvType = FloatType;
    type PtrConvType = PointerType;
}

impl IntMathType for VectorType {
    type ValueType = VectorValue;
    type MathConvType = VectorType;
    type PtrConvType = VectorType;
}

impl FloatMathType for FloatType {
    type ValueType = FloatValue;
    type MathConvType = IntType;
}

impl FloatMathType for VectorType {
    type ValueType = VectorValue;
    type MathConvType = VectorType;
}

impl PointerMathType for PointerType {
    type ValueType = PointerValue;
    type PtrConvType = IntType;
}

impl PointerMathType for VectorType {
    type ValueType = VectorValue;
    type PtrConvType = VectorType;
}
<commit_msg>Add doctests for BasicType functions<commit_after>use llvm_sys::prelude::LLVMTypeRef;

use std::fmt::Debug;

use crate::AddressSpace;
use crate::types::{IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VectorType, VoidType, Type};
use crate::types::enums::{AnyTypeEnum, BasicTypeEnum};
use crate::values::{IntMathValue, FloatMathValue, PointerMathValue, IntValue, FloatValue, PointerValue, VectorValue};

// This is an ugly privacy hack so that Type can stay private to this module
// and so that super traits using this trait will be not be implementable
// outside this library
pub trait AsTypeRef {
    fn as_type_ref(&self) -> LLVMTypeRef;
}

macro_rules! trait_type_set {
    ($trait_name:ident: $($args:ident),*) => (
        $(
            impl $trait_name for $args {}
        )*
    );
}

// REVIEW: print_to_string might be a good candidate to live here?
/// Represents any LLVM type.
pub trait AnyType: AsTypeRef + Debug {
    /// Returns an `AnyTypeEnum` that represents the current type.
    fn as_any_type_enum(&self) -> AnyTypeEnum {
        AnyTypeEnum::new(self.as_type_ref())
    }
}

/// Represents a basic LLVM type, that may be used in functions and struct definitions.
pub trait BasicType: AnyType {
    /// Returns a `BasicTypeEnum` that represents the current type.
    fn as_basic_type_enum(&self) -> BasicTypeEnum {
        BasicTypeEnum::new(self.as_type_ref())
    }

    /// Create a `FunctionType` with this `BasicType` as its return type.
    ///
    /// Example:
    /// ```
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.fn_type(&[], false), int.fn_type(&[], false));
    /// ```
    fn fn_type(&self, param_types: &[BasicTypeEnum], is_var_args: bool) -> FunctionType {
        Type::new(self.as_type_ref()).fn_type(param_types, is_var_args)
    }

    /// Create an `ArrayType` with this `BasicType` as its elements.
    ///
    /// Example:
    /// ```
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// assert_eq!(int_basic_type.array_type(32), int.array_type(32));
    /// ```
    fn array_type(&self, size: u32) -> ArrayType {
        Type::new(self.as_type_ref()).array_type(size)
    }

    /// Create a `PointerType` that points to this `BasicType`.
    ///
    /// Example:
    /// ```
    /// use inkwell::context::Context;
    /// use inkwell::types::BasicType;
    /// use inkwell::AddressSpace;
    ///
    /// let context = Context::create();
    /// let int = context.i32_type();
    /// let int_basic_type = int.as_basic_type_enum();
    /// let addr_space = AddressSpace::Generic;
    /// assert_eq!(int_basic_type.ptr_type(addr_space), int.ptr_type(addr_space));
    /// ```
    fn ptr_type(&self, address_space: AddressSpace) -> PointerType {
        Type::new(self.as_type_ref()).ptr_type(address_space)
    }
}

/// Represents an LLVM type that can have integer math operations applied to it.
pub trait IntMathType: BasicType {
    /// The value instance of an int or int vector type.
    type ValueType: IntMathValue;
    /// The type for int to float or int vector to float vector conversions.
    type MathConvType: FloatMathType;
    /// The type for int to pointer or int vector to pointer vector conversions.
    type PtrConvType: PointerMathType;
}

/// Represents an LLVM type that can have floating point math operations applied to it.
pub trait FloatMathType: BasicType {
    /// The value instance of a float or float vector type.
    type ValueType: FloatMathValue;
    /// The type for float to int or float vector to int vector conversions.
    type MathConvType: IntMathType;
}

/// Represents an LLVM type that can have pointer operations applied to it.
pub trait PointerMathType: BasicType {
    /// The value instance of a pointer type.
    type ValueType: PointerMathValue;
    /// The type for pointer to int or pointer vector to int conversions.
    type PtrConvType: IntMathType;
}

trait_type_set! {AnyType: AnyTypeEnum, BasicTypeEnum, IntType, FunctionType, FloatType, PointerType, StructType, ArrayType, VoidType, VectorType}
trait_type_set! {BasicType: BasicTypeEnum, IntType, FloatType, PointerType, StructType, ArrayType, VectorType}

impl IntMathType for IntType {
    type ValueType = IntValue;
    type MathConvType = FloatType;
    type PtrConvType = PointerType;
}

impl IntMathType for VectorType {
    type ValueType = VectorValue;
    type MathConvType = VectorType;
    type PtrConvType = VectorType;
}

impl FloatMathType for FloatType {
    type ValueType = FloatValue;
    type MathConvType = IntType;
}

impl FloatMathType for VectorType {
    type ValueType = VectorValue;
    type MathConvType = VectorType;
}

impl PointerMathType for PointerType {
    type ValueType = PointerValue;
    type PtrConvType = IntType;
}

impl PointerMathType for VectorType {
    type ValueType = VectorValue;
    type PtrConvType = VectorType;
}
<|endoftext|>


<commit_before>use bytes::{Buf, BufMut, BytesMut};
use hashing::hash;
use std::cmp::max;
use std::io::Cursor;

pub fn get_permutated_index(
    index: usize,
    list_size: usize,
    seed: &[u8],
    shuffle_round_count: usize,
) -> Option<usize> {
    if list_size == 0 || index >= list_size {
        return None;
    }

    let mut index = index;
    for round in 0..shuffle_round_count {
        let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size;
        let flip = (pivot + list_size - index) % list_size;
        let position = max(index, flip);
        let source = hash_with_round_and_position(seed, round, position);
        let byte = source[(position % 256) / 8];
        let bit = (byte >> (position % 8)) % 2;
        index = if bit == 1 { flip } else { index }
    }
    Some(index)
}

fn hash_with_round_and_position(seed: &[u8], round: usize, position: usize) -> Vec<u8> {
    let mut seed = seed.to_vec();
    seed.append(&mut int_to_bytes1(round as u64));
    seed.append(&mut int_to_bytes4(position as u64 / 256));
    hash(&seed[..])
}

fn hash_with_round(seed: &[u8], round: usize) -> Vec<u8> {
    let mut seed = seed.to_vec();
    seed.append(&mut int_to_bytes1(round as u64));
    hash(&seed[..])
}

fn int_to_bytes1(int: u64) -> Vec<u8> {
    let mut bytes = BytesMut::with_capacity(8);
    bytes.put_u64_le(int);
    vec![bytes[0]]
}

fn int_to_bytes4(int: u64) -> Vec<u8> {
    let mut bytes = BytesMut::with_capacity(8);
    bytes.put_u64_le(int);
    bytes[0..4].to_vec()
}

fn bytes_to_int64(bytes: &[u8]) -> u64 {
    let mut cursor = Cursor::new(bytes);
    cursor.get_u64_le()
}

#[cfg(test)]
mod tests {
    use super::*;
    use hex;
    use std::{fs::File, io::prelude::*, path::PathBuf};
    use yaml_rust::yaml;

    #[test]
    fn returns_none_for_zero_length_list() {
        assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90));
    }

    #[test]
    fn test_vectors() {
        /*
         * Test vectors are generated here:
         *
         * https://github.com/ethereum/eth2.0-test-generators
         */
        let mut file = {
            let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            file_path_buf.push("src/specs/test_vector_permutated_index.yml");

            File::open(file_path_buf).unwrap()
        };

        let mut yaml_str = String::new();

        file.read_to_string(&mut yaml_str).unwrap();

        let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
        let doc = &docs[0];
        let test_cases = doc["test_cases"].as_vec().unwrap();

        for (i, test_case) in test_cases.iter().enumerate() {
            let index = test_case["index"].as_i64().unwrap() as usize;
            let list_size = test_case["list_size"].as_i64().unwrap() as usize;
            let permutated_index = test_case["permutated_index"].as_i64().unwrap() as usize;
            let shuffle_round_count = test_case["shuffle_round_count"].as_i64().unwrap() as usize;
            let seed_string = test_case["seed"].clone().into_string().unwrap();
            let seed = hex::decode(seed_string.replace("0x", "")).unwrap();

            assert_eq!(
                Some(permutated_index),
                get_permutated_index(index, list_size, &seed[..], shuffle_round_count),
                "Failure on case #{} index: {}, list_size: {}, round_count: {}, seed: {}",
                i,
                index,
                list_size,
                shuffle_round_count,
                seed_string,
            );
        }
    }
}
<commit_msg>Updates to permutated_index<commit_after>use bytes::{Buf, BufMut, BytesMut};
use hashing::hash;
use std::cmp::max;
use std::io::Cursor;

/// Return `p(index)` in a pseudorandom permutation `p` of `0...list_size-1` with ``seed`` as entropy.
///
/// Utilizes 'swap or not' shuffling found in
/// https://link.springer.com/content/pdf/10.1007%2F978-3-642-32009-5_1.pdf
/// See the 'generalized domain' algorithm on page 3.
///
/// Returns `None` under any of the following conditions:
///  - `list_size == 0`
///  - `index >= list_size`
///  - `list_size >= usize::max_value() / 2`
pub fn get_permutated_index(
    index: usize,
    list_size: usize,
    seed: &[u8],
    shuffle_round_count: usize,
) -> Option<usize> {
    if list_size == 0 || index >= list_size || list_size >= usize::max_value() / 2 {
        return None;
    }

    let mut index = index;
    for round in 0..shuffle_round_count {
        let pivot = bytes_to_int64(&hash_with_round(seed, round)[..]) as usize % list_size;
        let flip = (pivot + list_size - index) % list_size;
        let position = max(index, flip);
        let source = hash_with_round_and_position(seed, round, position);
        let byte = source[(position % 256) / 8];
        let bit = (byte >> (position % 8)) % 2;
        index = if bit == 1 { flip } else { index }
    }
    Some(index)
}

fn hash_with_round_and_position(seed: &[u8], round: usize, position: usize) -> Vec<u8> {
    let mut seed = seed.to_vec();
    seed.append(&mut int_to_bytes1(round as u64));
    seed.append(&mut int_to_bytes4(position as u64 / 256));
    hash(&seed[..])
}

fn hash_with_round(seed: &[u8], round: usize) -> Vec<u8> {
    let mut seed = seed.to_vec();
    seed.append(&mut int_to_bytes1(round as u64));
    hash(&seed[..])
}

fn int_to_bytes1(int: u64) -> Vec<u8> {
    let mut bytes = BytesMut::with_capacity(8);
    bytes.put_u64_le(int);
    vec![bytes[0]]
}

fn int_to_bytes4(int: u64) -> Vec<u8> {
    let mut bytes = BytesMut::with_capacity(8);
    bytes.put_u64_le(int);
    bytes[0..4].to_vec()
}

fn bytes_to_int64(bytes: &[u8]) -> u64 {
    let mut cursor = Cursor::new(bytes);
    cursor.get_u64_le()
}

#[cfg(test)]
mod tests {
    use super::*;
    use hex;
    use std::{fs::File, io::prelude::*, path::PathBuf};
    use yaml_rust::yaml;

    #[test]
    fn returns_none_for_zero_length_list() {
        assert_eq!(None, get_permutated_index(100, 0, &[42, 42], 90));
    }

    #[test]
    fn returns_none_for_out_of_bounds_index() {
        assert_eq!(None, get_permutated_index(100, 100, &[42, 42], 90));
    }

    #[test]
    fn returns_none_for_too_large_list() {
        assert_eq!(
            None,
            get_permutated_index(100, usize::max_value() / 2, &[42, 42], 90)
        );
    }

    #[test]
    fn test_vectors() {
        /*
         * Test vectors are generated here:
         *
         * https://github.com/ethereum/eth2.0-test-generators
         */
        let mut file = {
            let mut file_path_buf = PathBuf::from(env!("CARGO_MANIFEST_DIR"));
            file_path_buf.push("src/specs/test_vector_permutated_index.yml");

            File::open(file_path_buf).unwrap()
        };

        let mut yaml_str = String::new();

        file.read_to_string(&mut yaml_str).unwrap();

        let docs = yaml::YamlLoader::load_from_str(&yaml_str).unwrap();
        let doc = &docs[0];
        let test_cases = doc["test_cases"].as_vec().unwrap();

        for (i, test_case) in test_cases.iter().enumerate() {
            let index = test_case["index"].as_i64().unwrap() as usize;
            let list_size = test_case["list_size"].as_i64().unwrap() as usize;
            let permutated_index = test_case["permutated_index"].as_i64().unwrap() as usize;
            let shuffle_round_count = test_case["shuffle_round_count"].as_i64().unwrap() as usize;
            let seed_string = test_case["seed"].clone().into_string().unwrap();
            let seed = hex::decode(seed_string.replace("0x", "")).unwrap();

            assert_eq!(
                Some(permutated_index),
                get_permutated_index(index, list_size, &seed[..], shuffle_round_count),
                "Failure on case #{} index: {}, list_size: {}, round_count: {}, seed: {}",
                i,
                index,
                list_size,
                shuffle_round_count,
                seed_string,
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::iter;
use field;
use field::{Pos, Field};

pub struct WavePruning {
  moves: Vec<Pos>,
  moves_field: Vec<Pos>
}

impl WavePruning {
  pub fn new(length: Pos) -> WavePruning {
    WavePruning {
      moves: Vec::with_capacity(length),
      moves_field: iter::repeat(0).take(length).collect()
    }
  }

  pub fn moves(&self) -> &Vec<Pos> {
    &self.moves
  }

  pub fn clear(&mut self) {
    self.moves.clear();
    for i in &mut self.moves_field {
      *i = 0;
    }
  }

  pub fn init(&mut self, field: &Field, radius: u32) {
    let width = field.width();
    for &start_pos in field.points_seq() {
      field::wave(width, start_pos, |pos| {
        if pos == start_pos && self.moves_field[pos] == 0 {
          self.moves_field[pos] = 1;
          true
        } else if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && field::manhattan(width, start_pos, pos) <= radius {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
      self.moves_field[start_pos] = 0;
    }
  }

  pub fn update(&mut self, field: &Field, last_moves_count: usize, radius: u32) -> Vec<Pos> {
    let moves_field = &mut self.moves_field;
    let moves = &mut self.moves;
    moves.retain(|&pos| {
      if field.is_putting_allowed(pos) {
        true
      } else {
        moves_field[pos] = 0;
        false
      }
    });
    let points_seq = field.points_seq();
    let width = field.width();
    let mut added_moves = Vec::new();
    for i in last_moves_count .. field.moves_count() {
      let next_pos = points_seq[i];
      field::wave(width, next_pos, |pos| {
        if pos == next_pos && moves_field[pos] == 0 {
          moves_field[pos] = 1;
          true
        } else if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && field::manhattan(width, next_pos, pos) <= radius {
          if moves_field[pos] == 0 && pos != next_pos {
            moves.push(pos);
            added_moves.push(pos);
          }
          moves_field[pos] = next_pos;
          true
        } else {
          false
        }
      });
      moves_field[next_pos] = 0;
    }
    added_moves
  }
}
<commit_msg>Fix clippy warning.<commit_after>use std::iter;
use field;
use field::{Pos, Field};

pub struct WavePruning {
  moves: Vec<Pos>,
  moves_field: Vec<Pos>
}

impl WavePruning {
  pub fn new(length: Pos) -> WavePruning {
    WavePruning {
      moves: Vec::with_capacity(length),
      moves_field: iter::repeat(0).take(length).collect()
    }
  }

  pub fn moves(&self) -> &Vec<Pos> {
    &self.moves
  }

  pub fn clear(&mut self) {
    self.moves.clear();
    for i in &mut self.moves_field {
      *i = 0;
    }
  }

  pub fn init(&mut self, field: &Field, radius: u32) {
    let width = field.width();
    for &start_pos in field.points_seq() {
      field::wave(width, start_pos, |pos| {
        if pos == start_pos && self.moves_field[pos] == 0 {
          self.moves_field[pos] = 1;
          true
        } else if self.moves_field[pos] != start_pos && field.is_putting_allowed(pos) && field::manhattan(width, start_pos, pos) <= radius {
          if self.moves_field[pos] == 0 {
            self.moves.push(pos);
          }
          self.moves_field[pos] = start_pos;
          true
        } else {
          false
        }
      });
      self.moves_field[start_pos] = 0;
    }
  }

  pub fn update(&mut self, field: &Field, last_moves_count: usize, radius: u32) -> Vec<Pos> {
    let moves_field = &mut self.moves_field;
    let moves = &mut self.moves;
    moves.retain(|&pos| {
      if field.is_putting_allowed(pos) {
        true
      } else {
        moves_field[pos] = 0;
        false
      }
    });
    let points_seq = field.points_seq();
    let width = field.width();
    let mut added_moves = Vec::new();
    for &next_pos in points_seq.iter().skip(last_moves_count) {
      field::wave(width, next_pos, |pos| {
        if pos == next_pos && moves_field[pos] == 0 {
          moves_field[pos] = 1;
          true
        } else if moves_field[pos] != next_pos && field.is_putting_allowed(pos) && field::manhattan(width, next_pos, pos) <= radius {
          if moves_field[pos] == 0 && pos != next_pos {
            moves.push(pos);
            added_moves.push(pos);
          }
          moves_field[pos] = next_pos;
          true
        } else {
          false
        }
      });
      moves_field[next_pos] = 0;
    }
    added_moves
  }
}
<|endoftext|>