<commit_before>use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, RwLock};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_state::DefaultState;

use std::mem;
use std::rc::Rc;
use linked_hash_map::LinkedHashMap;
use time::precise_time_s;
use fnv::FnvHasher;

use config::*;
use queue_backend::*;

#[derive(Debug)]
struct InFlightState {
    expiration: u32,
    retry: u32,
}

#[derive(Debug)]
pub struct Channel {
    tail: u64,
    message_count: u64,
    in_flight: LinkedHashMap<u64, InFlightState, DefaultState<FnvHasher>>
}

#[derive(Debug)]
pub struct Queue {
    config: Rc<QueueConfig>,
    // backend writes don't block readers
    // FIXME: queue_backend should handle it's concurrency access internally,
    // both for simplicity and performance
    backend_wlock: Mutex<()>,
    backend_rlock: RwLock<()>,
    backend: QueueBackend,
    channels: RwLock<HashMap<String, Mutex<Channel>, DefaultState<FnvHasher>>>,
    clock: u32
}

#[derive(Clone)]
pub struct ArcQueue(Arc<Queue>);

unsafe impl Sync for ArcQueue {}
unsafe impl Send for ArcQueue {}

impl Deref for ArcQueue {
    type Target = Queue;
    fn deref(&self) -> &Self::Target {
        &*self.0
    }
}

impl DerefMut for ArcQueue {
    #[allow(mutable_transmutes)]
    fn deref_mut(&mut self) -> &mut Self::Target {
        unsafe { mem::transmute(self.deref()) }
    }
}

impl ArcQueue {
    pub fn new(queue: Queue) -> ArcQueue {
        ArcQueue(Arc::new(queue))
    }
}

impl Queue {

    pub fn new(config: QueueConfig, recover: bool) -> Queue {
        let rc_config = Rc::new(config);
        let mut queue = Queue {
            config: rc_config.clone(),
            backend_wlock: Mutex::new(()),
            backend_rlock: RwLock::new(()),
            backend: QueueBackend::new(rc_config.clone(), recover),
            channels: RwLock::new(Default::default()),
            clock: 0,
        };
        queue.tick();
        queue
    }

    pub fn create_channel<S>(&mut self, channel_name: S) -> bool
            where String: From<S> {
        let channel_name: String = channel_name.into();
        let mut locked_channel = self.channels.write().unwrap();
        if let Entry::Vacant(vacant_entry) = locked_channel.entry(channel_name) {
            vacant_entry.insert(
                Mutex::new(
                    Channel {
                        tail: 0,
                        message_count: 0,
                        in_flight: Default::default()
                    }
                )
            );
            true
        } else {
            false
        }
    }

    pub fn delete_channel(&mut self, channel_name: &str) -> bool {
        let mut locked_channel = self.channels.write().unwrap();
        locked_channel.remove(channel_name).is_some()
    }

    /// get access is suposed to be thread-safe, even while writing
    pub fn get(&mut self, channel_name: &str) -> Option<Message> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let mut locked_channel = channel.lock().unwrap();

            // check in flight queue for timeouts
            if let Some((&id, &InFlightState { expiration, ..} )) = locked_channel.in_flight.front() {
                if self.clock >= expiration {
                    // FIXME: double get bellow, not ideal
                    let state = locked_channel.in_flight.get_refresh(&id).unwrap();
                    state.expiration = self.clock + self.config.time_to_live;
                    state.retry += 1;
                    trace!("[{}] msg {} expired and will be sent again", self.config.name, id);
                    return Some(self.backend.get(id).unwrap().1)
                }
            }

            // fetch from the backend
            if let Some((new_tail, message)) = self.backend.get(locked_channel.tail) {
                locked_channel.tail = new_tail;
                let state = InFlightState {
                    expiration: self.clock + self.config.time_to_live,
                    retry: 0
                };
                locked_channel.in_flight.insert(message.id, state);
                trace!("[{}] fetched msg {} from backend", self.config.name, message.id);
                return Some(message)
            }
        }
        None
    }

    /// all calls are serialized internally
    pub fn put(&mut self, message: &Message) -> Option<u64> {
        let _ = self.backend_wlock.lock().unwrap();
        trace!("[{}] putting message", self.config.name);
        self.backend.put(message)
    }

    /// delete access is suposed to be thread-safe, even while writing
    pub fn delete(&mut self, channel_name: &str, id: u64) -> Option<bool> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let removed_opt = channel.lock().unwrap().in_flight.remove(&id);
            trace!("[{}] message {} deleted from channel: {}",
                self.config.name, id, removed_opt.is_some());
            return Some(removed_opt.is_some())
        }
        None
    }

    pub fn purge(&mut self) {
        info!("[{}] purging", self.config.name);
        let _ = self.backend_rlock.write().unwrap();
        let _ = self.backend_wlock.lock().unwrap();
        self.backend.purge();
        self.channels.write().unwrap().clear();
    }

    pub fn maintenance(&mut self) {
        // add gc code here
    }

    pub fn tick(&mut self) {
        self.clock = precise_time_s() as u32;
        debug!("[{}] tick to {}", self.config.name, self.clock);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use config::*;
    use queue_backend::Message;
    use std::thread;
    use test;

    fn get_queue_opt(name: &str, recover: bool) -> Queue {
        let server_config = ServerConfig::read();
        let mut queue_config = server_config.new_queue_config(name);
        queue_config.time_to_live = 1;
        let mut queue = Queue::new(queue_config, recover);
        queue
    }

    fn get_queue() -> Queue {
        let thread = thread::current();
        let name = thread.name().unwrap().split("::").last().unwrap();
        get_queue_opt(name, false)
    }

    fn gen_message(id: u64) -> Message<'static> {
        Message {
            id: id,
            body: b"333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"
        }
    }

    fn init_logger() {
        use env_logger;
        env_logger::init();
    }

    #[test]
    fn test_fill() {
        let mut q = get_queue();
        let message = gen_message(0);
        for i in (0..100_000) {
            let r = q.put(&message);
            assert!(r.is_some());
        }
    }

    #[test]
    fn test_put_get() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test"));
        for i in (0..100_000) {
            assert!(q.put(&message).is_some());
            let m = q.get("test");
            assert!(m.is_some());
        }
    }

    #[test]
    fn test_create_channel() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_in_flight() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        // TODO: check in flight count
    }

    #[test]
    fn test_in_flight_timeout() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test") == true);
        assert!(q.put(&message).is_some());
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        thread::sleep_ms(1001);
        q.tick();
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_backend_recover() {
        init_logger();
        let mut q = get_queue_opt("test_reopen", false);
        let message = gen_message(0);
        let mut put_msg_count = 0;
        while q.backend.files_count() < 3 {
            assert!(q.put(&message).is_some());
            put_msg_count += 1;
        }
        drop(q);

        let mut q = get_queue_opt("test_reopen", true);
        assert!(q.create_channel("test") == true);
        assert_eq!(q.backend.files_count(), 3);
        let mut get_msg_count = 0;
        while let Some(_) = q.get("test") {
            get_msg_count += 1;
        }
        assert_eq!(get_msg_count, put_msg_count);
    }

    #[test]
    fn test_queue_recover() {
        // Add code here
    }

    #[bench]
    fn put_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let r = q.put(m);
                assert!(r.is_some());
            }
        });
    }

    #[bench]
    fn put_get_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        q.create_channel("test");
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let p = q.put(m);
                let r = q.get("test");
                assert_eq!(p.unwrap(), r.unwrap().id);
            }
        });
    }
}
<commit_msg>start maintenance code; no need to lock backend for deletes<commit_after>use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex, RwLock};
use std::collections::HashMap;
use std::collections::hash_map::Entry;
use std::collections::hash_state::DefaultState;

use std::mem;
use std::cmp;
use std::rc::Rc;
use linked_hash_map::LinkedHashMap;
use time::precise_time_s;
use fnv::FnvHasher;

use config::*;
use queue_backend::*;

#[derive(Debug)]
struct InFlightState {
    expiration: u32,
    retry: u32,
}

#[derive(Debug)]
pub struct Channel {
    tail: u64,
    message_count: u64,
    in_flight: LinkedHashMap<u64, InFlightState, DefaultState<FnvHasher>>
}

#[derive(Debug)]
pub struct Queue {
    config: Rc<QueueConfig>,
    // backend writes don't block readers
    // FIXME: queue_backend should handle it's concurrency access internally,
    // both for simplicity and performance
    backend_wlock: Mutex<()>,
    backend_rlock: RwLock<()>,
    backend: QueueBackend,
    channels: RwLock<HashMap<String, Mutex<Channel>, DefaultState<FnvHasher>>>,
    clock: u32
}

#[derive(Clone)]
pub struct ArcQueue(Arc<Queue>);

unsafe impl Sync for ArcQueue {}
unsafe impl Send for ArcQueue {}

impl Deref for ArcQueue {
    type Target = Queue;
    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

impl DerefMut for ArcQueue {
    #[allow(mutable_transmutes)]
    fn deref_mut(&mut self) -> &mut Self::Target {
        let queue: &Self::Target = self;
        unsafe { mem::transmute(queue) }
    }
}

impl ArcQueue {
    pub fn new(queue: Queue) -> ArcQueue {
        ArcQueue(Arc::new(queue))
    }
}

impl Queue {

    pub fn new(config: QueueConfig, recover: bool) -> Queue {
        let rc_config = Rc::new(config);
        let mut queue = Queue {
            config: rc_config.clone(),
            backend_wlock: Mutex::new(()),
            backend_rlock: RwLock::new(()),
            backend: QueueBackend::new(rc_config.clone(), recover),
            channels: RwLock::new(Default::default()),
            clock: 0,
        };
        queue.tick();
        queue
    }

    pub fn create_channel<S>(&mut self, channel_name: S) -> bool
            where String: From<S> {
        let channel_name: String = channel_name.into();
        let mut locked_channel = self.channels.write().unwrap();
        if let Entry::Vacant(vacant_entry) = locked_channel.entry(channel_name) {
            vacant_entry.insert(
                Mutex::new(
                    Channel {
                        tail: 0,
                        message_count: 0,
                        in_flight: Default::default()
                    }
                )
            );
            true
        } else {
            false
        }
    }

    pub fn delete_channel(&mut self, channel_name: &str) -> bool {
        let mut locked_channel = self.channels.write().unwrap();
        locked_channel.remove(channel_name).is_some()
    }

    /// get access is suposed to be thread-safe, even while writing
    pub fn get(&mut self, channel_name: &str) -> Option<Message> {
        let _ = self.backend_rlock.read().unwrap();
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let mut locked_channel = channel.lock().unwrap();

            // check in flight queue for timeouts
            if let Some((&id, &InFlightState { expiration, ..} )) = locked_channel.in_flight.front() {
                if self.clock >= expiration {
                    // FIXME: double get bellow, not ideal
                    let state = locked_channel.in_flight.get_refresh(&id).unwrap();
                    state.expiration = self.clock + self.config.time_to_live;
                    state.retry += 1;
                    trace!("[{}] msg {} expired and will be sent again", self.config.name, id);
                    return Some(self.backend.get(id).unwrap().1)
                }
            }

            // fetch from the backend
            // TODO: if we have incremental ids,
            //       we can add to in_flight and unlock the channel before fetching from backend
            if let Some((new_tail, message)) = self.backend.get(locked_channel.tail) {
                locked_channel.tail = new_tail;
                let state = InFlightState {
                    expiration: self.clock + self.config.time_to_live,
                    retry: 0
                };
                locked_channel.in_flight.insert(message.id, state);
                trace!("[{}] fetched msg {} from backend", self.config.name, message.id);
                return Some(message)
            }
        }
        None
    }

    /// all calls are serialized internally
    pub fn put(&mut self, message: &Message) -> Option<u64> {
        let _ = self.backend_wlock.lock().unwrap();
        trace!("[{}] putting message", self.config.name);
        self.backend.put(message)
    }

    /// delete access is suposed to be thread-safe, even while writing
    pub fn delete(&mut self, channel_name: &str, id: u64) -> Option<bool> {
        let locked_channels = self.channels.read().unwrap();
        if let Some(channel) = locked_channels.get(channel_name) {
            let removed_opt = channel.lock().unwrap().in_flight.remove(&id);
            trace!("[{}] message {} deleted from channel: {}",
                self.config.name, id, removed_opt.is_some());
            return Some(removed_opt.is_some())
        }
        None
    }

    pub fn purge(&mut self) {
        info!("[{}] purging", self.config.name);
        let _ = self.backend_rlock.write().unwrap();
        let _ = self.backend_wlock.lock().unwrap();
        self.backend.purge();
        self.channels.write().unwrap().clear();
    }

    pub fn maintenance(&mut self) {
        let smallest_tail = {
            let locked_channels = self.channels.read().unwrap();
            locked_channels.values().fold(0, |st, ch| {
                cmp::min(st, ch.lock().unwrap().tail)
            })
        };

        let _ = self.backend_rlock.read();
        self.backend.gc(smallest_tail);
    }

    fn tick(&mut self) {
        self.clock = precise_time_s() as u32;
    }

    pub fn tick_to(&mut self, clock: u32) {
        // FIXME: must ensure self.clock is within a single cache line
        self.clock = clock;
        debug!("[{}] tick to {}", self.config.name, self.clock);
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use config::*;
    use queue_backend::Message;
    use std::thread;
    use test;

    fn get_queue_opt(name: &str, recover: bool) -> Queue {
        let server_config = ServerConfig::read();
        let mut queue_config = server_config.new_queue_config(name);
        queue_config.time_to_live = 1;
        let mut queue = Queue::new(queue_config, recover);
        queue
    }

    fn get_queue() -> Queue {
        let thread = thread::current();
        let name = thread.name().unwrap().split("::").last().unwrap();
        get_queue_opt(name, false)
    }

    fn gen_message(id: u64) -> Message<'static> {
        Message {
            id: id,
            body: b"333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333333"
        }
    }

    fn init_logger() {
        use env_logger;
        env_logger::init();
    }

    #[test]
    fn test_fill() {
        let mut q = get_queue();
        let message = gen_message(0);
        for i in (0..100_000) {
            let r = q.put(&message);
            assert!(r.is_some());
        }
    }

    #[test]
    fn test_put_get() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test"));
        for i in (0..100_000) {
            assert!(q.put(&message).is_some());
            let m = q.get("test");
            assert!(m.is_some());
        }
    }

    #[test]
    fn test_create_channel() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_in_flight() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.get("test").is_none());
        assert!(q.put(&message).is_some());
        assert!(q.create_channel("test") == true);
        assert!(q.create_channel("test") == false);
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        // TODO: check in flight count
    }

    #[test]
    fn test_in_flight_timeout() {
        let mut q = get_queue();
        let message = gen_message(0);
        assert!(q.create_channel("test") == true);
        assert!(q.put(&message).is_some());
        assert!(q.get("test").is_some());
        assert!(q.get("test").is_none());
        thread::sleep_ms(1001);
        q.tick();
        assert!(q.get("test").is_some());
    }

    #[test]
    fn test_backend_recover() {
        init_logger();
        let mut q = get_queue_opt("test_reopen", false);
        let message = gen_message(0);
        let mut put_msg_count = 0;
        while q.backend.files_count() < 3 {
            assert!(q.put(&message).is_some());
            put_msg_count += 1;
        }
        drop(q);

        let mut q = get_queue_opt("test_reopen", true);
        assert!(q.create_channel("test") == true);
        assert_eq!(q.backend.files_count(), 3);
        let mut get_msg_count = 0;
        while let Some(_) = q.get("test") {
            get_msg_count += 1;
        }
        assert_eq!(get_msg_count, put_msg_count);
    }

    #[test]
    fn test_queue_recover() {
        // Add code here
    }

    #[bench]
    fn put_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let r = q.put(m);
                assert!(r.is_some());
            }
        });
    }

    #[bench]
    fn put_get_like_crazy(b: &mut test::Bencher) {
        let mut q = get_queue();
        let m = &gen_message(0);
        let n = 10000;
        q.create_channel("test");
        b.bytes = (m.body.len() * n) as u64;
        b.iter(|| {
            for _ in (0..n) {
                let p = q.put(m);
                let r = q.get("test");
                assert_eq!(p.unwrap(), r.unwrap().id);
            }
        });
    }
}
<|endoftext|>


<commit_before>extern crate std;
extern crate collections;
use std::io::File;
use std::io::BufferedReader;

fn getline(fname : &str, linenum : uint) -> ~str {
    let path = Path::new(fname);
    let mut i = 0;
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
        //print!("{}", line);
        i += 1;
        if i == linenum {
            return line.to_owned();
        }
    }
    return ~"not found";
}

fn is_path_char(c : char) -> bool {
    c.is_alphanumeric() || (c == '_') || (c == '!') || (c == ':')
}

fn is_ident_char(c : char) -> bool {
    c.is_alphanumeric() || (c == '_') || (c == '!')
}

fn expand_ident(s : &str, pos : uint) -> (uint,uint) {
    let sb = s.slice_to(pos);
    let mut start = pos;

    // backtrack to find start of word
    for (i, c) in sb.char_indices_rev() {
        if !is_ident_char(c) {
            break;
        }
        start = i;
    }
    return (start, pos);
}

fn expand_searchstr(s : &str, pos : uint) -> ~str {
    let sb = s.slice_to(pos);
    let mut start = pos;

    // backtrack to find start of word
    for (i, c) in sb.char_indices_rev() {
        if !is_path_char(c) {
            break;
        }
        start = i;
    }
    return s.slice(start,pos).to_owned();
}

fn find_end(s : &str, pos : uint) -> uint {
    // find end of word
    let sa = s.slice_from(pos);
    let mut end = pos;
    for (i, c) in sa.char_indices() {
        if !is_path_char(c) {
            break;
        }
        end = pos + i + 1;
    }
    return end;
}

fn find_in_module(path : &Path, s : &str, f : &|&str,&str|) {
    let mut file = BufferedReader::new(File::open(path));
    //let modsearchstr = "pub mod "+s;
    let modsearchstr = "mod ";
    let fnsearchstr = "fn ";
    let structsearchstr = "struct ";
    let cratesearchstr = "extern crate ";
    debug!("PHIL modsearchstr {}",modsearchstr + s);
    debug!("PHIL fnsearchstr {}",fnsearchstr + s);
    debug!("PHIL structsearchstr {}",structsearchstr + s);
    for line in file.lines() {
        match line.find_str(modsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+modsearchstr.len());
                let l = line.slice(n + modsearchstr.len(), end);
                (*f)(l, line);
            }
            None => {}
        }
        match line.find_str(fnsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+3);
                let l = line.slice(n + 3, end);
                (*f)(l + "(", line);
            }
            None => {}
        }
        match line.find_str(structsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+7);
                let l = line.slice(n+7, end);
                (*f)(l, line);
            }
            None => {}
        }

        match line.find_str(cratesearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+ cratesearchstr.len());
                let cratename = line.slice(n + cratesearchstr.len(), end);
                (*f)(cratename+"::", line)
            }
            None => {}
        }

        match line.find_str(s) {
            Some(_) => {
                match line.find_str("pub use ") {
                    Some(n) => {
                        let end = find_end(line, n+8);
                        let modname = line.slice(n+8, end);
                        debug!("PHIL modname is {}",modname);

                        if modname.starts_with("self::") {
                            let mut l = modname.split_str("::");
                            let c : ~[&str] = l.collect();
                            debug!("PHIL c {}",c);
                            if c.ends_with([""]) {
                                let mut c2 = c.slice_to(c.len()-1).to_owned();
                                c2.push(s);
                                search_f(path, c2.slice_from(1), f);
                            } else if c[c.len()-1].starts_with(s) {
                                search_f(path, c.slice_from(1), f);
                            }
                        }
                    }
                    None => {}
                }
            }
            None => {}
        }
    }
}

fn search_f(path : &Path, p : &[&str], f : &|&str,&str|) {
    debug!("search_f: {} {} ",path.as_str(),p);

    if p.len() == 1 {
        return find_in_module(path, p[0], f);
    }

    let mut file = BufferedReader::new(File::open(path));
    let modsearchstr = "mod ";
    for line in file.lines() {
        match line.find_str(modsearchstr + p[0]) {
            Some(n) => {
                let end = find_end(line, n+modsearchstr.len());
                let l = line.slice(n + modsearchstr.len(), end);
                if p.len() == 1 {
                    (*f)(l, line);
                } else {
                    debug!("PHIL NOT Found {} {} ",l,line);
                    let dir = path.dir_path();
                    debug!("PHIL DIR {}", dir.as_str().unwrap());
                    // try searching file.rs
                    search_f(&dir.join(l+".rs"), p.tail(), f);
                    // try searching dir/mod.rs
                    search_f(&dir.join_many([l, "mod.rs"]), p.tail(), f)
                }
            }
            None => {}
        }
    }
}

fn search_in_module(path : &Path, p : &[&str], f : &|&str,&str|) {
    let mut file = BufferedReader::new(File::open(path));
    for line in file.lines() {
        match line.find_str("use ") {
            Some(_) => {
                let mut s = line.slice_from(4).trim();

                match s.find_str(p[0]) {
                    Some(_) => {
                        let end = find_end(s, 0);
                        s = s.slice(0, end);
                        let pieces : ~[&str] = s.split_str("::").collect();
                        if p.len() == 1 && pieces[pieces.len()-1].starts_with(p[0]) {
                            search_crate(pieces, f);
                        } else if p.len() > 1 && pieces[pieces.len()-1] == p[0] {
                            let p2 = pieces + p.slice_from(1);
                            search_crate(p2, f);
                        }
                    }
                    None => {}
                }
            }
            None => {}
        }
    }
}

fn search_crates(path : &Path, p : &[&str], f : &|&str,&str|) {
    if p[0] == "std" {
        search_crate(p, f);
        return;
    }

    let mut file = BufferedReader::new(File::open(path));
    for line in file.lines() {
        let searchstr = "extern crate ";
        match line.find_str(searchstr+p[0]) {
            Some(n) => {
                let end = find_end(line, n+ searchstr.len());
                let cratename = line.slice(n + searchstr.len(), end);
                if p[0] == cratename {
                    search_crate(p, f);
                }
            }
            None => {}
        }
    }
}

fn search_crate(p : &[&str], f : &|&str,&str|) {
    let srcpaths = std::os::getenv("RUST_SRC_PATH").unwrap();
    let cratename = p[0];

    for srcpath in srcpaths.split_str(":") {
        {
            // try lib<cratename>/lib.rs, like in the rust source dir
            let cratelibname = "lib" + cratename;
            let path = Path::new(srcpath).join_many([Path::new(cratelibname),
                                                        Path::new("lib.rs")]);
            let ss = path.dirname_str().unwrap();
            debug!("PHIL path2 {}", ss);
            debug!("PHIL p {:?}",p.slice_from(1));
            search_f(&path, p.slice_from(1), f);
        }
        {
            // try <cratename>/<cratename>.rs, like in the servo codebase
            let path = Path::new(srcpath).join_many([Path::new(cratename),
                                                     Path::new("cratename.rs")]);
            search_f(&path, p.slice_from(1), f);
        }
        {
            // try <cratename>/lib.rs
            let path = Path::new(srcpath).join_many([Path::new("cratename"),
                                                     Path::new("lib.rs")]);
            search_f(&path, p.slice_from(1), f);
        }
        {
            // try just <cratename>.rs
            let path = Path::new(srcpath).join_many([Path::new("cratename.rs")]);
            search_f(&path, p.slice_from(1), f);
        }
    }
}

pub fn complete_from_file(fname : &str, linenum: uint, charnum: uint,
                          f : &|&str,&str|) {
    let line = getline(fname, linenum);
    let s = expand_searchstr(line, charnum);

    let mut l = s.split_str("::");
    let c : ~[&str] = l.collect();

    search_crates(&Path::new(fname), c, f);
    search_in_module(&Path::new(fname), c, f);
    search_f(&Path::new(fname), c, f);
}

fn print_usage() {
    let program = std::os::args()[0].clone();
    println!("usage: {} complete linenum charnum fname", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)",program);
    println!("or:    {} prefix linenum charnum fname",program);
}

fn complete() {
   match std::uint::parse_bytes(std::os::args()[2].as_bytes(), 10) {
        Some(n) => {
            // input: linenum, colnum, fname
            let linenum = n;
            let charnum = std::uint::parse_bytes(std::os::args()[3].as_bytes(), 10).unwrap();
            let fname = std::os::args()[4];

            // print the start-end of the identifier being matched
            let line = getline(fname, linenum);
            let (start, pos) = expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, line.slice(start, pos));

            complete_from_file(fname, linenum, charnum,
                 &|l, line| std::io::print("COMPLETE "+l + ","+line));
        }
        None => {
            // input: a command line string passed in
            let arg = std::os::args()[2];
            let mut it = arg.split_str("::");
            let p : ~[&str] = it.collect();
            search_crate(p, &|l, line| std::io::print("COMPLETE "+l + ","+line));
        }
    }
}

fn main() {
    match std::os::getenv("RUST_SRC_PATH") {
        Some(_) => {}
        None() => {
            println!("RUST_SRC_PATH environment variable must be set");
            return;
        }
    }

    let args = std::os::args().to_owned();

    if args.len() == 1 {
        print_usage();
        return;
    }

    let command = args[1];
    match  command {
        ~"prefix" => {
            let args = std::os::args().to_owned();
            let linenum = std::uint::parse_bytes(args[2].as_bytes(), 10).unwrap();
            let charnum = std::uint::parse_bytes(args[3].as_bytes(), 10).unwrap();
            let fname = args[4];

            // print the start, end, and the identifier prefix being matched
            let line = getline(fname, linenum);
            let (start, pos) = expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, line.slice(start, pos));
        }
        ~"complete" => complete(),
        ~"help" => print_usage(),
        _ => {
            println!("Sorry, I didn't understand command {}", command );
            print_usage();
            return;
        }
    }

 }

<commit_msg>Add line,fname to match output<commit_after>extern crate std;
extern crate collections;
use std::io::File;
use std::io::BufferedReader;

fn getline(fname : &str, linenum : uint) -> ~str {
    let path = Path::new(fname);
    let mut i = 0;
    let mut file = BufferedReader::new(File::open(&path));
    for line in file.lines() {
        //print!("{}", line);
        i += 1;
        if i == linenum {
            return line.to_owned();
        }
    }
    return ~"not found";
}

fn is_path_char(c : char) -> bool {
    c.is_alphanumeric() || (c == '_') || (c == '!') || (c == ':')
}

fn is_ident_char(c : char) -> bool {
    c.is_alphanumeric() || (c == '_') || (c == '!')
}

fn expand_ident(s : &str, pos : uint) -> (uint,uint) {
    let sb = s.slice_to(pos);
    let mut start = pos;

    // backtrack to find start of word
    for (i, c) in sb.char_indices_rev() {
        if !is_ident_char(c) {
            break;
        }
        start = i;
    }
    return (start, pos);
}

fn expand_searchstr(s : &str, pos : uint) -> ~str {
    let sb = s.slice_to(pos);
    let mut start = pos;

    // backtrack to find start of word
    for (i, c) in sb.char_indices_rev() {
        if !is_path_char(c) {
            break;
        }
        start = i;
    }
    return s.slice(start,pos).to_owned();
}

fn find_end(s : &str, pos : uint) -> uint {
    // find end of word
    let sa = s.slice_from(pos);
    let mut end = pos;
    for (i, c) in sa.char_indices() {
        if !is_path_char(c) {
            break;
        }
        end = pos + i + 1;
    }
    return end;
}

fn find_in_module(path : &Path, s : &str, matchfn : &|&str,int,&Path,&str|) {
    let mut file = BufferedReader::new(File::open(path));
    //let modsearchstr = "pub mod "+s;
    let modsearchstr = "mod ";
    let fnsearchstr = "fn ";
    let structsearchstr = "struct ";
    let cratesearchstr = "extern crate ";
    let mut i = 0;
    for line in file.lines() {
        i += 1;
        match line.find_str(modsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+modsearchstr.len());
                let l = line.slice(n + modsearchstr.len(), end);
                (*matchfn)(l, i, path, line);
            }
            None => {}
        }
        match line.find_str(fnsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+3);
                let l = line.slice(n + 3, end);
                (*matchfn)(l + "(", i, path, line);
            }
            None => {}
        }
        match line.find_str(structsearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+7);
                let l = line.slice(n+7, end);
                (*matchfn)(l, i, path, line);
            }
            None => {}
        }

        match line.find_str(cratesearchstr+s) {
            Some(n) => {
                let end = find_end(line, n+ cratesearchstr.len());
                let cratename = line.slice(n + cratesearchstr.len(), end);
                (*matchfn)(cratename+"::", i, path, line)
            }
            None => {}
        }

        match line.find_str(s) {
            Some(_) => {
                match line.find_str("pub use ") {
                    Some(n) => {
                        let end = find_end(line, n+8);
                        let modname = line.slice(n+8, end);

                        if modname.starts_with("self::") {
                            let mut l = modname.split_str("::");
                            let c : ~[&str] = l.collect();
                            if c.ends_with([""]) {
                                let mut c2 = c.slice_to(c.len()-1).to_owned();
                                c2.push(s);
                                search_f(path, c2.slice_from(1), matchfn);
                            } else if c[c.len()-1].starts_with(s) {
                                search_f(path, c.slice_from(1), matchfn);
                            }
                        }
                    }
                    None => {}
                }
            }
            None => {}
        }
    }
}

fn search_f(path: &Path, p: &[&str], matchfn: &|&str,int,&Path,&str|) {
    debug!("search_f: {} {} ",path.as_str(),p);

    if p.len() == 0 {
        return find_in_module(path, "", matchfn);
    }

    if p.len() == 1 {
        return find_in_module(path, p[0], matchfn);
    }

    let mut file = BufferedReader::new(File::open(path));
    let modsearchstr = "mod ";
    let mut i = 0;
    for line in file.lines() {
        i+=1;
        match line.find_str(modsearchstr + p[0]) {
            Some(n) => {
                let end = find_end(line, n+modsearchstr.len());
                let l = line.slice(n + modsearchstr.len(), end);
                if p.len() == 1 {
                    (*matchfn)(l, i, path,line);
                } else {
                    debug!("PHIL NOT Found {} {} ",l,line);
                    let dir = path.dir_path();
                    debug!("PHIL DIR {}", dir.as_str().unwrap());
                    // try searching file.rs
                    search_f(&dir.join(l+".rs"), p.tail(), matchfn);
                    // try searching dir/mod.rs
                    search_f(&dir.join_many([l, "mod.rs"]), p.tail(), matchfn)
                }
            }
            None => {}
        }
    }
}

fn search_in_module(path : &Path, p : &[&str], f : &|&str,int,&Path,&str|) {
    let mut file = BufferedReader::new(File::open(path));
    for line in file.lines() {
        match line.find_str("use ") {
            Some(_) => {
                let mut s = line.slice_from(4).trim();

                match s.find_str(p[0]) {
                    Some(_) => {
                        let end = find_end(s, 0);
                        s = s.slice(0, end);
                        let pieces : ~[&str] = s.split_str("::").collect();
                        if p.len() == 1 && pieces[pieces.len()-1].starts_with(p[0]) {
                            search_crate(pieces, f);
                        } else if p.len() > 1 && pieces[pieces.len()-1] == p[0] {
                            let p2 = pieces + p.slice_from(1);
                            search_crate(p2, f);
                        }
                    }
                    None => {}
                }
            }
            None => {}
        }
    }
}

fn search_crates(path : &Path, p : &[&str], matchfn : &|&str,int,&Path,&str|) {
    if p[0] == "std" {
        search_crate(p, matchfn);
        return;
    }

    let mut file = BufferedReader::new(File::open(path));
    for line in file.lines() {
        let searchstr = "extern crate ";
        match line.find_str(searchstr+p[0]) {
            Some(n) => {
                let end = find_end(line, n+ searchstr.len());
                let cratename = line.slice(n + searchstr.len(), end);
                if p[0] == cratename {
                    search_crate(p, matchfn);
                }
            }
            None => {}
        }
    }
}

fn search_crate(p : &[&str], matchfn : &|&str,int,&Path,&str|) {
    let srcpaths = std::os::getenv("RUST_SRC_PATH").unwrap();
    let cratename = p[0];

    for srcpath in srcpaths.split_str(":") {
        {
            // try lib<cratename>/lib.rs, like in the rust source dir
            let cratelibname = "lib" + cratename;
            let path = Path::new(srcpath).join_many([Path::new(cratelibname),
                                                        Path::new("lib.rs")]);
            search_f(&path, p.slice_from(1), matchfn);
        }
        {
            // try <cratename>/<cratename>.rs, like in the servo codebase
            let path = Path::new(srcpath).join_many([Path::new(cratename),
                                                     Path::new("cratename.rs")]);
            search_f(&path, p.slice_from(1), matchfn);
        }
        {
            // try <cratename>/lib.rs
            let path = Path::new(srcpath).join_many([Path::new("cratename"),
                                                     Path::new("lib.rs")]);
            search_f(&path, p.slice_from(1), matchfn);
        }
        {
            // try just <cratename>.rs
            let path = Path::new(srcpath).join_many([Path::new("cratename.rs")]);
            search_f(&path, p.slice_from(1), matchfn);
        }
    }
}

pub fn complete_from_file(fname : &str, linenum: uint, charnum: uint,
                          matchfn : &|&str,int,&Path,&str|) {
    let line = getline(fname, linenum);
    let s = expand_searchstr(line, charnum);

    let mut l = s.split_str("::");
    let c : ~[&str] = l.collect();

    search_crates(&Path::new(fname), c, matchfn);
    search_in_module(&Path::new(fname), c, matchfn);
    search_f(&Path::new(fname), c, matchfn);

    if c.len() == 1 && "std".starts_with(c[0]) {
        (*matchfn)("std::",1,&Path::new(fname),"std::");
    }

}

fn print_usage() {
    let program = std::os::args()[0].clone();
    println!("usage: {} complete linenum charnum fname", program);
    println!("or:    {} complete fullyqualifiedname   (e.g. std::io::)",program);
    println!("or:    {} prefix linenum charnum fname",program);
}

fn match_fn(l: &str, lineno: int, file:&Path,  linetxt: &str) {
    std::io::println("COMPLETE "+l +
                     "," + lineno.to_str() +
                     "," + file.as_str().unwrap() +
                     "," +  linetxt);
}

fn complete() {
   match std::uint::parse_bytes(std::os::args()[2].as_bytes(), 10) {
        Some(n) => {
            // input: linenum, colnum, fname
            let linenum = n;
            let charnum = std::uint::parse_bytes(std::os::args()[3].as_bytes(), 10).unwrap();
            let fname = std::os::args()[4];

            // print the start-end of the identifier being matched
            let line = getline(fname, linenum);
            let (start, pos) = expand_ident(line, charnum);
            println!("PREFIX {},{},{}", start, pos, line.slice(start, pos));

            complete_from_file(fname, linenum, charnum,
                  &|l, linenum, file, line| match_fn(l, linenum, file, line));
        }
        None => {
            // input: a command line string passed in
            let arg = std::os::args()[2];
            let mut it = arg.split_str("::");
            let p : ~[&str] = it.collect();
            search_crate(p,
                  &|l, linenum, file, line|  match_fn(l, linenum, file, line));
        }
    }
}

fn prefix() {
    let args = std::os::args().to_owned();
    let linenum = std::uint::parse_bytes(args[2].as_bytes(), 10).unwrap();
    let charnum = std::uint::parse_bytes(args[3].as_bytes(), 10).unwrap();
    let fname = args[4];

    // print the start, end, and the identifier prefix being matched
    let line = getline(fname, linenum);
    let (start, pos) = expand_ident(line, charnum);
    println!("PREFIX {},{},{}", start, pos, line.slice(start, pos));
}

fn main() {
    match std::os::getenv("RUST_SRC_PATH") {
        Some(_) => {}
        None() => {
            println!("RUST_SRC_PATH environment variable must be set");
            return;
        }
    }

    let args = std::os::args().to_owned();

    if args.len() == 1 {
        print_usage();
        return;
    }

    let command = args[1];
    match  command {
        ~"prefix" => prefix(),
        ~"complete" => complete(),
        ~"help" => print_usage(),
        _ => {
            println!("Sorry, I didn't understand command {}", command );
            print_usage();
            return;
        }
    }

 }

<|endoftext|>


<commit_before>//! This pass erases all early-bound regions from the types occurring in the MIR.
//! We want to do this once just before codegen, so codegen does not have to take
//! care erasing regions all over the place.
//! N.B., we do _not_ erase regions of statements that are relevant for
//! "types-as-contracts"-validation, namely, `AcquireValid` and `ReleaseValid`.

use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, TyContext};
use crate::transform::{MirPass, MirSource};

struct EraseRegionsVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl EraseRegionsVisitor<'tcx> {
    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
        EraseRegionsVisitor {
            tcx,
        }
    }
}

impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
        *ty = self.tcx.erase_regions(ty);
        self.super_ty(ty);
    }

    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
        *region = self.tcx.lifetimes.re_erased;
    }

    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
        *constant = self.tcx.erase_regions(constant);
    }

    fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
        *substs = self.tcx.erase_regions(substs);
    }
}

pub struct EraseRegions;

impl<'tcx> MirPass<'tcx> for EraseRegions {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
        EraseRegionsVisitor::new(tcx).visit_body(body);
    }
}
<commit_msg>super_ty on MutVisitor is empty so avoid the call<commit_after>//! This pass erases all early-bound regions from the types occurring in the MIR.
//! We want to do this once just before codegen, so codegen does not have to take
//! care erasing regions all over the place.
//! N.B., we do _not_ erase regions of statements that are relevant for
//! "types-as-contracts"-validation, namely, `AcquireValid` and `ReleaseValid`.

use rustc::ty::subst::SubstsRef;
use rustc::ty::{self, Ty, TyCtxt};
use rustc::mir::*;
use rustc::mir::visit::{MutVisitor, TyContext};
use crate::transform::{MirPass, MirSource};

struct EraseRegionsVisitor<'tcx> {
    tcx: TyCtxt<'tcx>,
}

impl EraseRegionsVisitor<'tcx> {
    pub fn new(tcx: TyCtxt<'tcx>) -> Self {
        EraseRegionsVisitor {
            tcx,
        }
    }
}

impl MutVisitor<'tcx> for EraseRegionsVisitor<'tcx> {
    fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
        *ty = self.tcx.erase_regions(ty);
    }

    fn visit_region(&mut self, region: &mut ty::Region<'tcx>, _: Location) {
        *region = self.tcx.lifetimes.re_erased;
    }

    fn visit_const(&mut self, constant: &mut &'tcx ty::Const<'tcx>, _: Location) {
        *constant = self.tcx.erase_regions(constant);
    }

    fn visit_substs(&mut self, substs: &mut SubstsRef<'tcx>, _: Location) {
        *substs = self.tcx.erase_regions(substs);
    }
}

pub struct EraseRegions;

impl<'tcx> MirPass<'tcx> for EraseRegions {
    fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) {
        EraseRegionsVisitor::new(tcx).visit_body(body);
    }
}
<|endoftext|>


<commit_before>use common::*;
use gl;
use gl::types::*;
use id_allocator::IdAllocator;
use state::EntityId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use yaglw::gl_context::{GLContext,GLContextExistence};
use yaglw::shader::Shader;
use yaglw::texture::BufferTexture;
use yaglw::texture::TextureUnit;

// VRAM bytes
pub const BYTE_BUDGET: uint = 78_000_000;
pub const POLYGON_COST: uint = 76;
// This assumes there exists only one set of TerrainVRAMBuffers.
pub const POLYGON_BUDGET: uint = BYTE_BUDGET / POLYGON_COST;

pub struct TerrainVRAMBuffers<'a> {
  id_to_index: HashMap<EntityId, uint>,
  index_to_id: Vec<EntityId>,

  empty_array: GLuint,
  length: uint,

  // Each position is buffered as 3 separate floats due to image format restrictions.
  vertex_positions: BufferTexture<'a, GLfloat>,
  // Each normal component is buffered separately floats due to image format restrictions.
  normals: BufferTexture<'a, GLfloat>,
  types: BufferTexture<'a, GLuint>,
}

impl<'a> TerrainVRAMBuffers<'a> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
  ) -> TerrainVRAMBuffers<'a> {
    TerrainVRAMBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      empty_array: unsafe {
        let mut empty_array = 0;
        gl::GenVertexArrays(1, &mut empty_array);
        empty_array
      },
      length: 0,
      // There are 3 R32F components per vertex.
      vertex_positions: BufferTexture::new(gl, gl_context, gl::R32F, 3 * VERTICES_PER_TRIANGLE * POLYGON_BUDGET),
      // There are 3 R32F components per normal.
      normals: BufferTexture::new(gl, gl_context, gl::R32F, 3 * VERTICES_PER_TRIANGLE * POLYGON_BUDGET),
      types: BufferTexture::new(gl, gl_context, gl::R32UI, POLYGON_BUDGET),
    }
  }

  pub fn bind_glsl_uniforms(
    &self,
    gl: &mut GLContext,
    texture_unit_alloc: &mut IdAllocator<TextureUnit>,
    shader: Rc<RefCell<Shader>>,
  ) {
    shader.borrow().use_shader(gl);
    let bind = |name, id| {
      let unit = texture_unit_alloc.allocate();
      unsafe {
        gl::ActiveTexture(unit.gl_id());
        gl::BindTexture(gl::TEXTURE_BUFFER, id);
      }
      let loc = shader.borrow_mut().get_uniform_location(name);
      unsafe {
        gl::Uniform1i(loc, unit.glsl_id as GLint);
      }
    };

    bind("positions", self.vertex_positions.handle.gl_id);
    bind("normals", self.normals.handle.gl_id);
    bind("terrain_types", self.types.handle.gl_id);
  }

  pub fn push(
    &mut self,
    gl: &mut GLContext,
    vertices: &[GLfloat],
    normals: &[GLfloat],
    types: &[GLuint],
    ids: &[EntityId],
  ) {
    assert_eq!(vertices.len(), 3 * VERTICES_PER_TRIANGLE * ids.len());
    assert_eq!(normals.len(), vertices.len());
    assert_eq!(types.len(), ids.len());

    for &id in ids.iter() {
      self.id_to_index.insert(id, self.index_to_id.len());
      self.index_to_id.push(id);
    }

    self.length += 3 * ids.len();
    self.vertex_positions.buffer.byte_buffer.bind(gl);
    self.vertex_positions.buffer.push(gl, vertices);
    self.normals.buffer.byte_buffer.bind(gl);
    self.normals.buffer.push(gl, normals);
    self.types.buffer.byte_buffer.bind(gl);
    self.types.buffer.push(gl, types);
  }

  // Note: `id` must be present in the buffers.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: EntityId) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.length -= 3;
    self.vertex_positions.buffer.byte_buffer.bind(gl);
    self.vertex_positions.buffer.swap_remove(gl, idx * 3 * VERTICES_PER_TRIANGLE, 3 * VERTICES_PER_TRIANGLE);
    self.normals.buffer.byte_buffer.bind(gl);
    self.normals.buffer.swap_remove(gl, 3 * idx * VERTICES_PER_TRIANGLE, 3 * VERTICES_PER_TRIANGLE);
    self.types.buffer.byte_buffer.bind(gl);
    self.types.buffer.swap_remove(gl, idx, 1);
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.empty_array);
      gl::DrawArrays(gl::TRIANGLES, 0, self.length as GLint);
    }
  }
}
<commit_msg>Tweak VRAM down a tiny bit.<commit_after>use common::*;
use gl;
use gl::types::*;
use id_allocator::IdAllocator;
use state::EntityId;
use std::cell::RefCell;
use std::collections::HashMap;
use std::rc::Rc;
use yaglw::gl_context::{GLContext,GLContextExistence};
use yaglw::shader::Shader;
use yaglw::texture::BufferTexture;
use yaglw::texture::TextureUnit;

// VRAM bytes
pub const BYTE_BUDGET: uint = 76_000_000;
pub const POLYGON_COST: uint = 76;
// This assumes there exists only one set of TerrainVRAMBuffers.
pub const POLYGON_BUDGET: uint = BYTE_BUDGET / POLYGON_COST;

pub struct TerrainVRAMBuffers<'a> {
  id_to_index: HashMap<EntityId, uint>,
  index_to_id: Vec<EntityId>,

  empty_array: GLuint,
  length: uint,

  // Each position is buffered as 3 separate floats due to image format restrictions.
  vertex_positions: BufferTexture<'a, GLfloat>,
  // Each normal component is buffered separately floats due to image format restrictions.
  normals: BufferTexture<'a, GLfloat>,
  types: BufferTexture<'a, GLuint>,
}

impl<'a> TerrainVRAMBuffers<'a> {
  pub fn new(
    gl: &'a GLContextExistence,
    gl_context: &mut GLContext,
  ) -> TerrainVRAMBuffers<'a> {
    TerrainVRAMBuffers {
      id_to_index: HashMap::new(),
      index_to_id: Vec::new(),
      empty_array: unsafe {
        let mut empty_array = 0;
        gl::GenVertexArrays(1, &mut empty_array);
        empty_array
      },
      length: 0,
      // There are 3 R32F components per vertex.
      vertex_positions: BufferTexture::new(gl, gl_context, gl::R32F, 3 * VERTICES_PER_TRIANGLE * POLYGON_BUDGET),
      // There are 3 R32F components per normal.
      normals: BufferTexture::new(gl, gl_context, gl::R32F, 3 * VERTICES_PER_TRIANGLE * POLYGON_BUDGET),
      types: BufferTexture::new(gl, gl_context, gl::R32UI, POLYGON_BUDGET),
    }
  }

  pub fn bind_glsl_uniforms(
    &self,
    gl: &mut GLContext,
    texture_unit_alloc: &mut IdAllocator<TextureUnit>,
    shader: Rc<RefCell<Shader>>,
  ) {
    shader.borrow().use_shader(gl);
    let bind = |name, id| {
      let unit = texture_unit_alloc.allocate();
      unsafe {
        gl::ActiveTexture(unit.gl_id());
        gl::BindTexture(gl::TEXTURE_BUFFER, id);
      }
      let loc = shader.borrow_mut().get_uniform_location(name);
      unsafe {
        gl::Uniform1i(loc, unit.glsl_id as GLint);
      }
    };

    bind("positions", self.vertex_positions.handle.gl_id);
    bind("normals", self.normals.handle.gl_id);
    bind("terrain_types", self.types.handle.gl_id);
  }

  pub fn push(
    &mut self,
    gl: &mut GLContext,
    vertices: &[GLfloat],
    normals: &[GLfloat],
    types: &[GLuint],
    ids: &[EntityId],
  ) {
    assert_eq!(vertices.len(), 3 * VERTICES_PER_TRIANGLE * ids.len());
    assert_eq!(normals.len(), vertices.len());
    assert_eq!(types.len(), ids.len());

    for &id in ids.iter() {
      self.id_to_index.insert(id, self.index_to_id.len());
      self.index_to_id.push(id);
    }

    self.length += 3 * ids.len();
    self.vertex_positions.buffer.byte_buffer.bind(gl);
    self.vertex_positions.buffer.push(gl, vertices);
    self.normals.buffer.byte_buffer.bind(gl);
    self.normals.buffer.push(gl, normals);
    self.types.buffer.byte_buffer.bind(gl);
    self.types.buffer.push(gl, types);
  }

  // Note: `id` must be present in the buffers.
  pub fn swap_remove(&mut self, gl: &mut GLContext, id: EntityId) {
    let idx = *self.id_to_index.get(&id).unwrap();
    let swapped_id = self.index_to_id[self.index_to_id.len() - 1];
    self.index_to_id.swap_remove(idx);
    self.id_to_index.remove(&id);

    if id != swapped_id {
      self.id_to_index.insert(swapped_id, idx);
    }

    self.length -= 3;
    self.vertex_positions.buffer.byte_buffer.bind(gl);
    self.vertex_positions.buffer.swap_remove(gl, idx * 3 * VERTICES_PER_TRIANGLE, 3 * VERTICES_PER_TRIANGLE);
    self.normals.buffer.byte_buffer.bind(gl);
    self.normals.buffer.swap_remove(gl, 3 * idx * VERTICES_PER_TRIANGLE, 3 * VERTICES_PER_TRIANGLE);
    self.types.buffer.byte_buffer.bind(gl);
    self.types.buffer.swap_remove(gl, idx, 1);
  }

  pub fn draw(&self, _gl: &mut GLContext) {
    unsafe {
      gl::BindVertexArray(self.empty_array);
      gl::DrawArrays(gl::TRIANGLES, 0, self.length as GLint);
    }
  }
}
<|endoftext|>


<commit_before>use core::cell::Cell;
use core::task::PlatformThread;
use core::task;

type MainFunction = ~fn();

fn key(_: @MainFunction) {}

#[no_mangle]
#[cfg(target_os="macos")]
pub extern fn SDL_main(_: c_int, _: **c_char) {
    unsafe {
        (*local_data::local_data_get(key).get())();
    }
}

#[cfg(target_os="macos")]
pub fn start(main: MainFunction) {
    let cell = Cell(main);
    do task::task().sched_mode(PlatformThread).spawn {
        let args = os::args();
        unsafe {
            local_data::local_data_set(key, @cell.take());

            // XXX: Use return value to set program return code.
            // XXX: This isn't really safe... args might not be null-
            // terminated.
            let c_args = args.map(|s| -> *c_char { transmute(&s[0]) });
            let _ = SDLX_main(args.len() as c_int, &c_args[0]);
        }
    }
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
pub fn start(main: MainFunction) {
    let cell = Cell(main);
    do task::task().sched_mode(PlatformThread).spawn {
        cell.take()();
    }
}

#[cfg(target_os="macos")]
#[link_args="-L. -lSDLXmain -framework AppKit -framework Foundation"]
extern {
    fn SDLX_main(argc: c_int, argv: **c_char) -> c_int;
}
<commit_msg>Reintroduced missing imports. Whoops.<commit_after>use core::cast::transmute;
use core::cell::Cell;
use core::libc::{c_char, c_int};
use core::task::PlatformThread;
use core::task::local_data;
use core::task;

type MainFunction = ~fn();

fn key(_: @MainFunction) {}

#[no_mangle]
#[cfg(target_os="macos")]
pub extern fn SDL_main(_: c_int, _: **c_char) {
    unsafe {
        (*local_data::local_data_get(key).get())();
    }
}

#[cfg(target_os="macos")]
pub fn start(main: MainFunction) {
    let cell = Cell(main);
    do task::task().sched_mode(PlatformThread).spawn {
        let args = os::args();
        unsafe {
            local_data::local_data_set(key, @cell.take());

            // XXX: Use return value to set program return code.
            // XXX: This isn't really safe... args might not be null-
            // terminated.
            let c_args = args.map(|s| -> *c_char { transmute(&s[0]) });
            let _ = SDLX_main(args.len() as c_int, &c_args[0]);
        }
    }
}

#[cfg(target_os="win32")]
#[cfg(target_os="linux")]
#[cfg(target_os="freebsd")]
pub fn start(main: MainFunction) {
    let cell = Cell(main);
    do task::task().sched_mode(PlatformThread).spawn {
        cell.take()();
    }
}

#[cfg(target_os="macos")]
#[link_args="-L. -lSDLXmain -framework AppKit -framework Foundation"]
extern {
    fn SDLX_main(argc: c_int, argv: **c_char) -> c_int;
}
<|endoftext|>


<commit_before>//! The state of the program including interactions (moving around), last query, search
//! results and current selection

use crate::common::{Prompt, Text};
use crate::fuzzy::Candidate;

/// Possible updates done to the State
#[derive(Debug, Clone)]
pub enum StateUpdate {
    /// The query has changed
    Query,
    /// Any other update
    All,
}

impl Default for StateUpdate {
    fn default() -> Self {
        Self::All
    }
}

/// Current state of the program
#[derive(Debug, Clone, Default)]
pub struct State {
    search: Option<Prompt>,
    matches: Vec<Candidate>,
    pool_len: usize,
    selection_idx: usize,
    last_update: StateUpdate,
}

impl State {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn set_search(&mut self, search: Prompt) {
        self.search = Some(search);
        self.last_update = StateUpdate::Query;
    }

    pub fn query(&self) -> String {
        match &self.search {
            Some(sb) => sb.as_string(),
            None => "".into(),
        }
    }

    pub fn cursor_until_end(&self) -> usize {
        match &self.search {
            Some(sb) => sb.cursor_until_end(),
            None => 0,
        }
    }

    pub fn set_matches(&mut self, matches: (Vec<Candidate>, usize)) {
        self.matches = matches.0;
        self.pool_len = matches.1;

        if self.selection_idx >= self.max_selection() {
            self.selection_idx = self.max_selection();
        }

        self.last_update = StateUpdate::All;
    }

    pub fn matches(&self) -> &Vec<Candidate> {
        &self.matches
    }

    pub fn pool_len(&self) -> usize {
        self.pool_len
    }

    pub fn last_update(&self) -> &StateUpdate {
        &self.last_update
    }

    pub fn select_up(&mut self) {
        if self.selection_idx == 0 {
            self.selection_idx = self.max_selection();
        } else {
            self.selection_idx -= 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn select_down(&mut self) {
        if self.selection_idx == self.max_selection() {
            self.selection_idx = 0;
        } else {
            self.selection_idx += 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn selection_idx(&self) -> usize {
        self.selection_idx
    }

    pub fn selection(&self) -> Option<Text> {
        match self.matches.get(self.selection_idx) {
            Some(candidate) => Some(candidate.text.clone()),
            None => None,
        }
    }

    fn max_selection(&self) -> usize {
        let len = self.matches.len();

        if len == 0 {
            0
        } else {
            len - 1
        }
    }
}
<commit_msg>Fix clippy:manual-map warning<commit_after>//! The state of the program including interactions (moving around), last query, search
//! results and current selection

use crate::common::{Prompt, Text};
use crate::fuzzy::Candidate;

/// Possible updates done to the State
#[derive(Debug, Clone)]
pub enum StateUpdate {
    /// The query has changed
    Query,
    /// Any other update
    All,
}

impl Default for StateUpdate {
    fn default() -> Self {
        Self::All
    }
}

/// Current state of the program
#[derive(Debug, Clone, Default)]
pub struct State {
    search: Option<Prompt>,
    matches: Vec<Candidate>,
    pool_len: usize,
    selection_idx: usize,
    last_update: StateUpdate,
}

impl State {
    pub fn new() -> Self {
        Self::default()
    }

    pub fn set_search(&mut self, search: Prompt) {
        self.search = Some(search);
        self.last_update = StateUpdate::Query;
    }

    pub fn query(&self) -> String {
        match &self.search {
            Some(sb) => sb.as_string(),
            None => "".into(),
        }
    }

    pub fn cursor_until_end(&self) -> usize {
        match &self.search {
            Some(sb) => sb.cursor_until_end(),
            None => 0,
        }
    }

    pub fn set_matches(&mut self, matches: (Vec<Candidate>, usize)) {
        self.matches = matches.0;
        self.pool_len = matches.1;

        if self.selection_idx >= self.max_selection() {
            self.selection_idx = self.max_selection();
        }

        self.last_update = StateUpdate::All;
    }

    pub fn matches(&self) -> &Vec<Candidate> {
        &self.matches
    }

    pub fn pool_len(&self) -> usize {
        self.pool_len
    }

    pub fn last_update(&self) -> &StateUpdate {
        &self.last_update
    }

    pub fn select_up(&mut self) {
        if self.selection_idx == 0 {
            self.selection_idx = self.max_selection();
        } else {
            self.selection_idx -= 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn select_down(&mut self) {
        if self.selection_idx == self.max_selection() {
            self.selection_idx = 0;
        } else {
            self.selection_idx += 1;
        }
        self.last_update = StateUpdate::All;
    }

    pub fn selection_idx(&self) -> usize {
        self.selection_idx
    }

    pub fn selection(&self) -> Option<Text> {
        self.matches.get(self.selection_idx).map(|candidate| candidate.text.clone())
    }

    fn max_selection(&self) -> usize {
        let len = self.matches.len();

        if len == 0 {
            0
        } else {
            len - 1
        }
    }
}
<|endoftext|>


<commit_before>extern crate rand;
use table::rand::Rng;
type Bucket = Vec<usize>; // later this will have chaining, for now just blob
 // everything together
const P: f64 = (0xFFFFFFFE as usize - 4) as f64;
pub struct LSHTable<'a, T: 'a, Q: 'a+?Sized>  {
    buckets: Vec<Bucket>,
    data: &'a Vec<T>,
    hash_functions: &'a Vec<Box<Q>>,
    ri1: Vec<f64>,
    ri2: Vec<f64>
}

impl<'a, T, Q: 'a+?Sized> LSHTable<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn new(data: &'a Vec<T>, hashes: &'a Vec<Box<Q>>) -> Self {
        LSHTable {
            buckets: vec![Vec::new(); data.len()],
            data: data,
            hash_functions: hashes,
            ri1: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            ri2: rand::thread_rng().gen_iter().take(hashes.len()).collect()
        }
    }
    fn get_signature(&self, v: &'a T) -> Vec<f64> {
        self.hash_functions.iter().map(|x| {
            (*x)(v)
        }).collect()
    }
    pub fn new_build(data: &'a Vec<T>, hashes: &'a Vec<Box<Q>>) -> Self {
        let mut x_to_build = LSHTable::new(data, hashes);
        for (i, v) in x_to_build.data.iter().enumerate() {
            let hash_sig = x_to_build.get_signature(v);
            let bucket_ind = hash_func_t1(&hash_sig, &x_to_build.ri1, P, x_to_build.buckets.len());
            x_to_build.buckets[bucket_ind].push(i);
        }
        x_to_build
    }
}

fn hash_func_t1(signature: &Vec<f64>, rand_ints: &Vec<f64>, primes: f64, num_buckets: usize) -> usize {
    //let total: usize = ((signature.iter().zip(rand_ints).map(|(a, b)| {(a * b) as usize}).sum()) as usize) % primes;
    let total: usize = {
        let mut counter: f64 = 0.0;
        for element in signature.iter().zip(rand_ints).map(|(a, b)| {(a * b)}) {
            counter = ((counter + element)) % primes;
        }
        counter as usize
    };
    total % num_buckets
}

#[cfg(test)]
mod tests {
    use super::LSHTable;
    #[test]
    fn test_init() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let x = LSHTable::new(&test_data, &funcs);
    }
    #[test]
    fn test_new_build() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let x = LSHTable::new_build(&test_data, &funcs);
    }
}
<commit_msg>querying works! 😀<commit_after>extern crate rand;
use table::rand::Rng;
type Bucket = Vec<usize>; // later this will have chaining, for now just blob
 // everything together
const P: f64 = (0xFFFFFFFE as usize - 4) as f64;
pub struct LSHTable<'a, T: 'a, Q: 'a+?Sized>  {
    buckets: Vec<Bucket>,
    data: &'a Vec<T>,
    hash_functions: &'a Vec<Box<Q>>,
    ri1: Vec<f64>,
    ri2: Vec<f64>
}

impl<'a, T, Q: 'a+?Sized> LSHTable<'a, T, Q> where Q: Fn(&'a T) -> f64 {
    pub fn new(data: &'a Vec<T>, hashes: &'a Vec<Box<Q>>) -> Self {
        LSHTable {
            buckets: vec![Vec::new(); data.len()],
            data: data,
            hash_functions: hashes,
            ri1: rand::thread_rng().gen_iter().take(hashes.len()).collect(),
            ri2: rand::thread_rng().gen_iter().take(hashes.len()).collect()
        }
    }
    fn get_signature(&self, v: &'a T) -> Vec<f64> {
        self.hash_functions.iter().map(|x| {
            (*x)(v)
        }).collect()
    }
    pub fn new_build(data: &'a Vec<T>, hashes: &'a Vec<Box<Q>>) -> Self {
        let mut x_to_build = LSHTable::new(data, hashes);
        for (i, v) in x_to_build.data.iter().enumerate() {
            let hash_sig = x_to_build.get_signature(v);
            let bucket_ind = hash_func_t1(&hash_sig, &x_to_build.ri1, P, x_to_build.buckets.len());
            x_to_build.buckets[bucket_ind].push(i);
        }
        x_to_build
    }

    pub fn query_vec(&self, v: &'a T) -> Vec<&T> {
        let sig = self.get_signature(v);
        let sig_ind = hash_func_t1(&sig, &self.ri1, P, self.buckets.len());
        self.buckets[sig_ind].iter().map(|bucket_ind| {
            &self.data[*bucket_ind]
        }).collect()
    }
}

fn hash_func_t1(signature: &Vec<f64>, rand_ints: &Vec<f64>, primes: f64, num_buckets: usize) -> usize {
    let total: usize = {
        let mut counter: f64 = 0.0;
        for element in signature.iter().zip(rand_ints).map(|(a, b)| {(a * b)}) {
            counter = ((counter + element)) % primes;
        }
        counter as usize
    };
    total % num_buckets
}

#[cfg(test)]
mod tests {
    use super::LSHTable;
    #[test]
    fn test_init() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let x = LSHTable::new(&test_data, &funcs);
    }
    #[test]
    fn test_new_build() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let x = LSHTable::new_build(&test_data, &funcs);
    }

    #[test]
    fn test_query() {
        let test_data = vec![
            vec![1,2,3,4,5],
            vec![0,0,0,0,0],
            vec![1,2,3,4,5]
        ];

        let val = |q: &Vec<i32>| {0.0 as f64};
        let funcs = vec![Box::new(val)];
        let x = LSHTable::new_build(&test_data, &funcs);
        x.query_vec(&test_data[0]);
    }
}
<|endoftext|>


<commit_before>use std::io::fs::{mod, PathExtensions};
use std::io::USER_DIR;
use std::rt::unwind;
use std::path::Path;

use core::{mod, EnvBuilder, DbFlags, EnvNoMemInit, EnvNoMetaSync};

fn test_db_in_path(path: &Path, f: ||) {
    // Delete dir to be sure nothing existed before test
    if path.exists() {
        let _ = fs::rmdir_recursive(path);
    };

    let _ = unsafe { unwind::try(f) };

    let _ = fs::rmdir_recursive(path);
}

#[test]
fn test_environment() {
    let path = Path::new("test-lmdb");
    test_db_in_path(&path, || {
        // It looks pretty tree like, because it is the simplest test and
        // it expected to produce easy traceable results
        let env = EnvBuilder::new()
            .max_readers(33)
            .open(&path, USER_DIR);

        match env {
            Ok(mut env) => {
                match env.sync(true) {
                    Ok(..) => (),
                    Err(err) => fail!("Failed to sync: {}", err)
                };

                let test_flags = EnvNoMemInit | EnvNoMetaSync;

                match env.set_flags(test_flags, true) {
                    Ok(_) => {
                        match env.get_flags() {
                            Ok(new_flags) => assert!((new_flags & test_flags) == test_flags, "Get flags != set flags"),
                            Err(err) => fail!("Failed to get flags: {}", err)
                        }
                    },
                    Err(err) => fail!("Failed to set flags: {}", err)
                };

                match env.get_default_db(DbFlags::empty()) {
                    Ok(db) => {
                        let key = "hello".to_string();
                        let value = "world".to_string();

                        match env.new_transaction() {
                            Ok(txn) => {
                                match db.set(&txn, &key, &value) {
                                    Ok(_) => {
                                        match db.get::<String>(&txn, &key) {
                                            Ok(v) => assert!(v.as_slice() == value.as_slice(), "Written {:?} and read {:?}", value.as_slice(), v.as_slice()),
                                            Err(err) => fail!("Failed to read value: {}", err)
                                        }
                                    },
                                    Err(err) => fail!("Failed to write value: {}", err)
                                }
                            },
                            Err(err) => fail!("Failed to create transaction: {}", err)
                        }
                    },
                    Err(err) => fail!("Failed to get default database: {}", err)
                }
            },
            Err(err) => fail!("Failed to open path {}: {}", path.display(), err)
        };
    });
}

#[test]
fn test_single_values() {
    let path = Path::new("single-values");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(DbFlags::empty()).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        let _ = db.set(&txn, &test_key1, &test_data1);
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "Data written differs from data read");

        let _ = db.set(&txn, &test_key1, &test_data2);
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data2.as_slice(), "Data written differs from data read");

        let _ = db.del(&txn, &test_key1);
        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key should be deleted");
    });
}

#[test]
fn test_multiple_values() {
    let path = Path::new("multiple-values");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        let _ = db.set(&txn, &test_key1, &test_data1);
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "Data written differs from data read");

        let _ = db.set(&txn, &test_key1, &test_data2);
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "It should still return first value");

        let _ = db.del_item(&txn, &test_key1, &test_data1);

        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data2.as_slice(), "It should return second value");
        let _ = db.del(&txn, &test_key1);

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist anymore!");
    });
}

#[test]
fn test_cursors() {
    let path = Path::new("cursors");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_key2 = "key2".to_string();
        let test_values: Vec<String> = vec!("value1".to_string(), "value2".to_string(), "value3".to_string(), "value4".to_string());

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        for t in test_values.iter() {
            let _ = db.set(&txn, &test_key1, t);
            let _ = db.set(&txn, &test_key2, t);
        }

        let mut cursor = db.new_cursor(&txn).unwrap();
        assert!(cursor.to_first().is_ok());

        assert!(cursor.to_key(&test_key1).is_ok());
        assert!(cursor.item_count().unwrap() == 4);

        assert!(cursor.del_item().is_ok());
        assert!(cursor.item_count().unwrap() == 3);

        assert!(cursor.to_key(&test_key1).is_ok());
        let new_value = "testme".to_string();

        assert!(cursor.set(&new_value).is_ok());
        let (_, v): ((), String) = cursor.get().unwrap();

        // NOTE: this asserting will work once new_value is
        // of the same length as it is inplace change
        assert!(v.as_slice() == new_value.as_slice());

        assert!(cursor.del_all().is_ok());
        assert!(cursor.to_key(&test_key1).is_err());

        assert!(cursor.to_key(&test_key2).is_ok());
    });
}

#[test]
fn test_item_iter() {
    let path = Path::new("item_iter");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();
        let test_key2 = "key2".to_string();
        let test_key3 = "key3".to_string();

        let _ = db.set(&txn, &test_key1, &test_data1);
        let _ = db.set(&txn, &test_key1, &test_data2);
        let _ = db.set(&txn, &test_key2, &test_data1);

        let iter = db.item_iter(&txn, &test_key1).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.as_slice(), vec![test_data1.clone(), test_data2.clone()].as_slice());

        let iter = db.item_iter(&txn, &test_key2).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.as_slice(), vec![test_data1.clone()].as_slice());

        let iter = db.item_iter(&txn, &test_key3).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.len(), 0);
    });
}

#[test]
fn test_db_creation() {
    let path = Path::new("dbs");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();
        assert!(env.get_or_create_db("test-db", DbFlags::empty()).is_ok());
    });
}

/*
#[test]
fn test_env_clone() {
let path = Path::new("clone");
test_db_in_path(&path, || {
let mut env = Environment::new().unwrap();
assert!(env.set_maxdbs(5).is_ok());
assert!(env.open(&path, EnvFlags::empty(), 0o755).is_ok());

let env2 = env;

env.set_maxdbs(4);
        });
    }
     */

    /*

    #[test]
    fn test_compilation_of_moved_items() {
        let path = Path::new("dbcom");
        test_db_in_path(&path, || {
            let mut env = Environment::new().unwrap();
            assert!(env.set_maxdbs(5).is_ok());
            assert!(env.open(&path, 0, 0o755).is_ok());

            let db = env.get_default_db(0).unwrap();
            let mut txn = env.new_transaction().unwrap();

            txn.commit();

            let test_key1 = "key1";
            let test_data1 = "value1";

            assert!(txn.get::<()>(&db, &test_key1).is_err(), "Key shouldn't exist yet");
        })
    }
     */
<commit_msg>Minor test updates<commit_after>use std::io::fs::{mod, PathExtensions};
use std::io::USER_DIR;
use std::rt::unwind;
use std::path::Path;

use core::{mod, EnvBuilder, DbFlags, EnvNoMemInit, EnvNoMetaSync};

fn test_db_in_path(path: &Path, f: ||) {
    // Delete dir to be sure nothing existed before test
    if path.exists() {
        let _ = fs::rmdir_recursive(path);
    };

    let _ = unsafe { unwind::try(f) };

    let _ = fs::rmdir_recursive(path);
}

#[test]
fn test_environment() {
    let path = Path::new("test-lmdb");
    test_db_in_path(&path, || {
        // It looks pretty tree like, because it is the simplest test and
        // it expected to produce easy traceable results
        let env = EnvBuilder::new()
            .max_readers(33)
            .open(&path, USER_DIR);

        match env {
            Ok(mut env) => {
                match env.sync(true) {
                    Ok(..) => (),
                    Err(err) => fail!("Failed to sync: {}", err)
                };

                let test_flags = EnvNoMemInit | EnvNoMetaSync;

                match env.set_flags(test_flags, true) {
                    Ok(_) => {
                        match env.get_flags() {
                            Ok(new_flags) => assert!((new_flags & test_flags) == test_flags, "Get flags != set flags"),
                            Err(err) => fail!("Failed to get flags: {}", err)
                        }
                    },
                    Err(err) => fail!("Failed to set flags: {}", err)
                };

                match env.get_default_db(DbFlags::empty()) {
                    Ok(db) => {
                        let key = "hello".to_string();
                        let value = "world".to_string();

                        match env.new_transaction() {
                            Ok(txn) => {
                                match db.set(&txn, &key, &value) {
                                    Ok(_) => {
                                        match db.get::<String>(&txn, &key) {
                                            Ok(v) => assert!(v.as_slice() == value.as_slice(), "Written {:?} and read {:?}", value.as_slice(), v.as_slice()),
                                            Err(err) => fail!("Failed to read value: {}", err)
                                        }
                                    },
                                    Err(err) => fail!("Failed to write value: {}", err)
                                }
                            },
                            Err(err) => fail!("Failed to create transaction: {}", err)
                        }
                    },
                    Err(err) => fail!("Failed to get default database: {}", err)
                }
            },
            Err(err) => fail!("Failed to open path {}: {}", path.display(), err)
        };
    });
}

#[test]
fn test_single_values() {
    let path = Path::new("single-values");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(DbFlags::empty()).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        assert!(db.set(&txn, &test_key1, &test_data1).is_ok());
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "Data written differs from data read");

        assert!(db.set(&txn, &test_key1, &test_data2).is_ok());
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data2.as_slice(), "Data written differs from data read");

        assert!(db.del(&txn, &test_key1).is_ok());
        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key should be deleted");
    });
}

#[test]
fn test_multiple_values() {
    let path = Path::new("multiple-values");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        assert!(db.set(&txn, &test_key1, &test_data1).is_ok());
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "Data written differs from data read");

        assert!(db.set(&txn, &test_key1, &test_data2).is_ok());
        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data1.as_slice(), "It should still return first value");

        assert!(db.del_item(&txn, &test_key1, &test_data1).is_ok());

        let v: String = db.get(&txn, &test_key1).unwrap();
        assert!(v.as_slice() == test_data2.as_slice(), "It should return second value");
        assert!(db.del(&txn, &test_key1).is_ok());

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist anymore!");
    });
}

#[test]
fn test_cursors() {
    let path = Path::new("cursors");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_key2 = "key2".to_string();
        let test_values: Vec<String> = vec!("value1".to_string(), "value2".to_string(), "value3".to_string(), "value4".to_string());

        assert!(db.get::<()>(&txn, &test_key1).is_err(), "Key shouldn't exist yet");

        for t in test_values.iter() {
            let _ = db.set(&txn, &test_key1, t);
            let _ = db.set(&txn, &test_key2, t);
        }

        let mut cursor = db.new_cursor(&txn).unwrap();
        assert!(cursor.to_first().is_ok());

        assert!(cursor.to_key(&test_key1).is_ok());
        assert!(cursor.item_count().unwrap() == 4);

        assert!(cursor.del_item().is_ok());
        assert!(cursor.item_count().unwrap() == 3);

        assert!(cursor.to_key(&test_key1).is_ok());
        let new_value = "testme".to_string();

        assert!(cursor.set(&new_value).is_ok());
        let (_, v): ((), String) = cursor.get().unwrap();

        // NOTE: this asserting will work once new_value is
        // of the same length as it is inplace change
        assert!(v.as_slice() == new_value.as_slice());

        assert!(cursor.del_all().is_ok());
        assert!(cursor.to_key(&test_key1).is_err());

        assert!(cursor.to_key(&test_key2).is_ok());
    });
}

#[test]
fn test_item_iter() {
    let path = Path::new("item_iter");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();

        let db = env.get_default_db(core::DbAllowDups).unwrap();
        let txn = env.new_transaction().unwrap();

        let test_key1 = "key1".to_string();
        let test_data1 = "value1".to_string();
        let test_data2 = "value2".to_string();
        let test_key2 = "key2".to_string();
        let test_key3 = "key3".to_string();

        assert!(db.set(&txn, &test_key1, &test_data1).is_ok());
        assert!(db.set(&txn, &test_key1, &test_data2).is_ok());
        assert!(db.set(&txn, &test_key2, &test_data1).is_ok());

        let iter = db.item_iter(&txn, &test_key1).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.as_slice(), vec![test_data1.clone(), test_data2.clone()].as_slice());

        let iter = db.item_iter(&txn, &test_key2).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.as_slice(), vec![test_data1.clone()].as_slice());

        let iter = db.item_iter(&txn, &test_key3).unwrap();
        let values: Vec<String> = iter.map(|cv| cv.get_value()).collect();
        assert_eq!(values.len(), 0);
    });
}

#[test]
fn test_db_creation() {
    let path = Path::new("dbs");
    test_db_in_path(&path, || {
        let env = EnvBuilder::new()
            .max_dbs(5)
            .open(&path, USER_DIR)
            .unwrap();
        assert!(env.get_or_create_db("test-db", DbFlags::empty()).is_ok());
    });
}

/*
#[test]
fn test_env_clone() {
let path = Path::new("clone");
test_db_in_path(&path, || {
let mut env = Environment::new().unwrap();
assert!(env.set_maxdbs(5).is_ok());
assert!(env.open(&path, EnvFlags::empty(), 0o755).is_ok());

let env2 = env;

env.set_maxdbs(4);
        });
    }
     */

    /*

    #[test]
    fn test_compilation_of_moved_items() {
        let path = Path::new("dbcom");
        test_db_in_path(&path, || {
            let mut env = Environment::new().unwrap();
            assert!(env.set_maxdbs(5).is_ok());
            assert!(env.open(&path, 0, 0o755).is_ok());

            let db = env.get_default_db(0).unwrap();
            let mut txn = env.new_transaction().unwrap();

            txn.commit();

            let test_key1 = "key1";
            let test_data1 = "value1";

            assert!(txn.get::<()>(&db, &test_key1).is_err(), "Key shouldn't exist yet");
        })
    }
     */
<|endoftext|>