<commit_before>extern crate cdc;
extern crate ring;

#[macro_use]
extern crate arrayref;

use std::io::prelude::*;
use std::io::{self, BufReader, SeekFrom};
use std::fs::File;

use cdc::*;
use ring::digest;

pub struct DigestReader<R> {
    inner: R,
    pub digest: digest::Context,
}

impl<R: Read> DigestReader<R> {
    pub fn new(inner: R, digest: digest::Context) -> DigestReader<R> {
        DigestReader {
            inner: inner,
            digest: digest,
        }
    }
}

impl<R: Read> Read for DigestReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let size = try!(self.inner.read(buf));
        self.digest.update(&buf[0..size]);
        Ok(size)
    }
}

fn file_chunk_reader(path: &String, chunk: &Chunk) -> io::Result<io::Take<BufReader<File>>> {
    let mut file = try!(File::open(path));
    try!(file.seek(SeekFrom::Start(chunk.index)));
    Ok(BufReader::new(file).take(chunk.size))
}

type Hash256 = [u8; 256/8];

fn new_hash_node(level: usize, children: &Vec<Hash256>) -> Node<Hash256> {
    let mut ctx = digest::Context::new(&digest::SHA256);
    for child in children {
        ctx.update(child);
    }
    let digest = ctx.finish();
    let hash: Hash256 = array_ref![digest.as_ref(), 0, 256/8].clone();

    Node {
        hash: hash,
        level: level,
        children: children.clone()
    }
}

fn chunk_file(path: &String) -> io::Result<()> {
    // Opens the file and gets the byte_iter.
    let f = try!(File::open(path));
    let stream_length = f.metadata().unwrap().len();
    let reader: BufReader<File> = BufReader::new(f);
    let byte_iter = reader.bytes().map(|b| b.unwrap());

    // Iterates on the separators.
    let separator_iter = SeparatorIter::new(byte_iter);

    // Iterates on the chunks.
    let chunk_iter = ChunkIter::new(separator_iter, stream_length);

    // Converts into hashed chunks.
    let hashed_chunk_iter = chunk_iter.map(|chunk| {
        // Calculates the sha256 of the chunks.
        let chunk_reader = file_chunk_reader(path, &chunk).unwrap();
        let mut digest_reader = DigestReader::new(chunk_reader, digest::Context::new(&digest::SHA256));
        io::copy(&mut digest_reader, &mut io::sink()).unwrap();
        let digest = digest_reader.digest.finish();
        let hash: Hash256 = array_ref![digest.as_ref(), 0, 256/8].clone();

        // Calculates the level of the separators.
        let level = HashToLevel::custom_new(13, 3).to_level(chunk.separator_hash);

        HashedChunk {
            hash: hash,
            level: level,
        }
    });

    // Builds a tree of hash nodes.
    let mut nb_nodes = 0u64;
    let mut total_children = 0u64;
    let mut level_counts = vec![];
    for node in NodeIter::new(hashed_chunk_iter, new_hash_node, 0) {
        //println!("{:?}", node.level);
        nb_nodes += 1;
        total_children += node.children.len() as u64;

        if node.level >= level_counts.len() {
            level_counts.resize(node.level + 1, 0);
        }
        level_counts[node.level] += 1;
    }
    println!("Total number of nodes: {}.", nb_nodes);
    println!("Average number of children: {}.", total_children / nb_nodes);
    println!("Level counts: {:?}.", level_counts);

	Ok(())
}

fn main() {
	chunk_file(&"myLargeFile.bin".to_owned()).unwrap();
}
<commit_msg>Added an extra byte to differentiate the nodes and the leaves. This byte should be used for sha-256 calculation and should also be serialised in the blob. However, it should not be including when deserialising the blobs, nodes or leaves.<commit_after>extern crate cdc;
extern crate ring;

#[macro_use]
extern crate arrayref;

use std::io::prelude::*;
use std::io::{self, BufReader, SeekFrom};
use std::fs::File;

use cdc::*;
use ring::digest;

pub struct DigestReader<R> {
    inner: R,
    pub digest: digest::Context,
}

impl<R: Read> DigestReader<R> {
    pub fn new(inner: R, digest: digest::Context) -> DigestReader<R> {
        DigestReader {
            inner: inner,
            digest: digest,
        }
    }
}

impl<R: Read> Read for DigestReader<R> {
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let size = try!(self.inner.read(buf));
        self.digest.update(&buf[0..size]);
        Ok(size)
    }
}

fn file_chunk_reader(path: &String, chunk: &Chunk) -> io::Result<io::Take<BufReader<File>>> {
    let mut file = try!(File::open(path));
    try!(file.seek(SeekFrom::Start(chunk.index)));
    Ok(BufReader::new(file).take(chunk.size))
}

type Hash256 = [u8; 256/8];

fn new_hash_node(level: usize, children: &Vec<Hash256>) -> Node<Hash256> {
    let mut ctx = digest::Context::new(&digest::SHA256);
    ctx.update(&[1u8]); // To mark that it is a node, not a chunk.
    for child in children {
        ctx.update(child);
    }
    let digest = ctx.finish();
    let hash: Hash256 = array_ref![digest.as_ref(), 0, 256/8].clone();

    Node {
        hash: hash,
        level: level,
        children: children.clone()
    }
}

fn chunk_file(path: &String) -> io::Result<()> {
    // Opens the file and gets the byte_iter.
    let f = try!(File::open(path));
    let stream_length = f.metadata().unwrap().len();
    let reader: BufReader<File> = BufReader::new(f);
    let byte_iter = reader.bytes().map(|b| b.unwrap());

    // Iterates on the separators.
    let separator_iter = SeparatorIter::new(byte_iter);

    // Iterates on the chunks.
    let chunk_iter = ChunkIter::new(separator_iter, stream_length);

    // Converts into hashed chunks.
    let hashed_chunk_iter = chunk_iter.map(|chunk| {
        // Calculates the sha256 of the chunks.
        let chunk_reader = file_chunk_reader(path, &chunk).unwrap();
        let mut digest_reader = DigestReader::new(chunk_reader, digest::Context::new(&digest::SHA256));
        digest_reader.digest.update(&[0u8]); // To mark that it is a chunk, not a node.
        io::copy(&mut digest_reader, &mut io::sink()).unwrap();
        let digest = digest_reader.digest.finish();
        let hash: Hash256 = array_ref![digest.as_ref(), 0, 256/8].clone();

        // Calculates the level of the separators.
        let level = HashToLevel::custom_new(13, 3).to_level(chunk.separator_hash);

        HashedChunk {
            hash: hash,
            level: level,
        }
    });

    // Builds a tree of hash nodes.
    let mut nb_nodes = 0u64;
    let mut total_children = 0u64;
    let mut level_counts = vec![];
    for node in NodeIter::new(hashed_chunk_iter, new_hash_node, 0) {
        println!("Node: {{level: {}, children.len(): {}}}", node.level, node.children.len());
        nb_nodes += 1;
        total_children += node.children.len() as u64;

        if node.level >= level_counts.len() {
            level_counts.resize(node.level + 1, 0);
        }
        level_counts[node.level] += 1;
    }
    println!("Total number of nodes: {}.", nb_nodes);
    println!("Average number of children: {}.", total_children / nb_nodes);
    println!("Level counts: {:?}.", level_counts);

	Ok(())
}

fn main() {
	chunk_file(&"myLargeFile.bin".to_owned()).unwrap();
}
<|endoftext|>


<commit_before>use raft::{SyncClient, ClientClusterInfo, RaftMsg, RaftStateMachine, LogEntry, ClientQryResponse};
use raft::state_machine::OpType;
use std::collections::{HashMap, BTreeMap, HashSet};
use std::iter::FromIterator;
use std::sync::Mutex;
use std::sync::atomic::{AtomicU64, Ordering};
use std::cell::RefCell;
use bifrost_plugins::hash_str;
use rand;

const ORDERING: Ordering = Ordering::Relaxed;

struct QryMeta {
    last_log_id: AtomicU64,
    last_log_term: AtomicU64,
    pos: AtomicU64
}

struct Members {
    clients: BTreeMap<u64, Mutex<SyncClient>>,
    id_map: HashMap<u64, String>,
}

pub struct RaftClient {
    qry_meta: QryMeta,
    members: Members,
    term: u64, // last member list update term
}

impl RaftClient {
    pub fn new(servers: Vec<String>) -> Option<RaftClient> {
        let mut client = RaftClient {
            qry_meta: QryMeta {
                last_log_id: AtomicU64::new(0),
                last_log_term: AtomicU64::new(0),
                pos: AtomicU64::new(rand::random::<u64>())
            },
            members: Members {
                clients: BTreeMap::new(),
                id_map: HashMap::new()
            },
            term: 0,
        };
        match client.update_info(&HashSet::from_iter(servers)) {
            Ok(_) => Some(client),
            Err(_) => None
        }
    }

    fn update_info(&mut self, addrs: &HashSet<String>) -> Result<(), ()> {
        let info: ClientClusterInfo;
        let mut servers = None;
        for server_addr in addrs {
            let id = hash_str(server_addr.clone());
            let mut client = self.members.clients.entry(id).or_insert_with(|| {
                Mutex::new(SyncClient::new(server_addr))
            });
            if let Some(Ok(info)) = client.lock().unwrap().c_server_cluster_info() {
                servers = Some(info);
                break;
            }
        }
        match servers {
            Some(servers) => {
                let remote_members = servers.members;
                let mut remote_ids = HashSet::with_capacity(remote_members.len());
                self.members.id_map.clear();
                for (id, addr) in remote_members {
                    self.members.id_map.insert(id, addr);
                    remote_ids.insert(id);
                }
                let mut connected_ids = HashSet::with_capacity(self.members.clients.len());
                for id in self.members.clients.keys() {connected_ids.insert(*id);}
                let ids_to_remove = connected_ids.difference(&remote_ids);
                for id in ids_to_remove {self.members.clients.remove(id);}
                for id in remote_ids.difference(&connected_ids) {
                    let addr = self.members.id_map.get(id).unwrap();
                    self.members.clients.entry(id.clone()).or_insert_with(|| {
                        Mutex::new(SyncClient::new(addr))
                    });
                }
                Ok(())
            },
            None => Err(()),
        }
    }

    pub fn execute<R>(&self, sm: RaftStateMachine, msg: &RaftMsg<R>) -> Option<R> {
        let (fn_id, op, req_data) = msg.encode();
        let sm_id = sm.id;
        let response = match op {
            OpType::QUERY => {

            },
            OpType::COMMAND => {

            },
        };
        None
    }

    fn query(&self, sm_id: u64, fn_id: u64, data: &Vec<u8>) -> Option<Vec<u8>> {
        let pos = self.qry_meta.pos.fetch_add(1, ORDERING);
        let clients_count = self.members.clients.len();
        let res = {
            let mut client = self.members.clients.values()
                .nth(pos as usize % clients_count)
                .unwrap().lock().unwrap();
            client.c_query(LogEntry {
                id: self.qry_meta.last_log_id.load(ORDERING),
                term: self.qry_meta.last_log_term.load(ORDERING),
                sm_id: sm_id,
                fn_id: fn_id,
                data: data.clone()
            })
        };
        match res {
            Some(Ok(res)) => {
                match res {
                    ClientQryResponse::LeftBehind => {
                        self.query(sm_id, fn_id, data)
                    },
                    ClientQryResponse::Success{
                        data: data,
                        last_log_term: last_log_term,
                        last_log_id: last_log_id
                    } => {
                        swap_when_larger(&self.qry_meta.last_log_id, last_log_id);
                        swap_when_larger(&self.qry_meta.last_log_term, last_log_term);
                        Some(data)
                    },
                }
            },
            _ => None
        }
    }
}

fn swap_when_larger(atomic: &AtomicU64, value: u64) {
    let mut orig_num = atomic.load(ORDERING);
    loop {
        if orig_num >= value {
            return;
        }
        let actual = atomic.compare_and_swap(orig_num, value, ORDERING);
        if actual == orig_num {
            return;
        } else {
            orig_num = actual;
        }
    }
}<commit_msg>completely mut free client<commit_after>use raft::{SyncClient, ClientClusterInfo, RaftMsg, RaftStateMachine, LogEntry, ClientQryResponse};
use raft::state_machine::OpType;
use std::collections::{HashMap, BTreeMap, HashSet};
use std::iter::FromIterator;
use std::sync::{Mutex, RwLock};
use std::sync::atomic::{AtomicU64, Ordering};
use std::cell::RefCell;
use bifrost_plugins::hash_str;
use rand;

const ORDERING: Ordering = Ordering::Relaxed;

struct QryMeta {
    pos: AtomicU64
}

struct Members {
    clients: BTreeMap<u64, Mutex<SyncClient>>,
    id_map: HashMap<u64, String>,
}

pub struct RaftClient {
    qry_meta: QryMeta,
    members: RwLock<Members>,
    leader_id: AtomicU64,
    last_log_id: AtomicU64,
    last_log_term: AtomicU64,
}

impl RaftClient {
    pub fn new(servers: Vec<String>) -> Option<RaftClient> {
        let mut client = RaftClient {
            qry_meta: QryMeta {
                pos: AtomicU64::new(rand::random::<u64>())
            },
            members: RwLock::new(Members {
                clients: BTreeMap::new(),
                id_map: HashMap::new()
            }),
            leader_id: AtomicU64::new(0),
            last_log_id: AtomicU64::new(0),
            last_log_term: AtomicU64::new(0),
        };
        match client.update_info(&HashSet::from_iter(servers)) {
            Ok(_) => Some(client),
            Err(_) => None
        }
    }

    fn update_info(&self, addrs: &HashSet<String>) -> Result<(), ()> {
        let info: ClientClusterInfo;
        let mut servers = None;
        let mut members = self.members.write().unwrap();
        for server_addr in addrs {
            let id = hash_str(server_addr.clone());
            let mut client = members.clients.entry(id).or_insert_with(|| {
                Mutex::new(SyncClient::new(server_addr))
            });
            if let Some(Ok(info)) = client.lock().unwrap().c_server_cluster_info() {
                servers = Some(info);
                break;
            }
        }
        match servers {
            Some(servers) => {
                let remote_members = servers.members;
                let mut remote_ids = HashSet::with_capacity(remote_members.len());
                members.id_map.clear();
                for (id, addr) in remote_members {
                    members.id_map.insert(id, addr);
                    remote_ids.insert(id);
                }
                let mut connected_ids = HashSet::with_capacity(members.clients.len());
                for id in members.clients.keys() {connected_ids.insert(*id);}
                let ids_to_remove = connected_ids.difference(&remote_ids);
                for id in ids_to_remove {members.clients.remove(id);}
                for id in remote_ids.difference(&connected_ids) {
                    let addr = members.id_map.get(id).unwrap().clone();
                    members.clients.entry(id.clone()).or_insert_with(|| {
                        Mutex::new(SyncClient::new(&addr))
                    });
                }
                Ok(())
            },
            None => Err(()),
        }
    }

    pub fn execute<R>(&self, sm: RaftStateMachine, msg: &RaftMsg<R>) -> Option<R> {
        let (fn_id, op, req_data) = msg.encode();
        let sm_id = sm.id;
        let response = match op {
            OpType::QUERY => {

            },
            OpType::COMMAND => {

            },
        };
        None
    }

    fn query(&self, sm_id: u64, fn_id: u64, data: &Vec<u8>) -> Option<Vec<u8>> {
        let pos = self.qry_meta.pos.fetch_add(1, ORDERING);
        let res = {
            let members = self.members.read().unwrap();
            let mut client = {
                let clients_count = members.clients.len();
                members.clients.values()
                    .nth(pos as usize % clients_count)
                    .unwrap().lock().unwrap()
            };
            client.c_query(LogEntry {
                id: self.last_log_id.load(ORDERING),
                term: self.last_log_term.load(ORDERING),
                sm_id: sm_id,
                fn_id: fn_id,
                data: data.clone()
            })
        };
        match res {
            Some(Ok(res)) => {
                match res {
                    ClientQryResponse::LeftBehind => {
                        self.query(sm_id, fn_id, data)
                    },
                    ClientQryResponse::Success{
                        data: data,
                        last_log_term: last_log_term,
                        last_log_id: last_log_id
                    } => {
                        swap_when_larger(&self.last_log_id, last_log_id);
                        swap_when_larger(&self.last_log_term, last_log_term);
                        Some(data)
                    },
                }
            },
            _ => None
        }
    }

//    fn command(&self, sm_id: u64, fn_id: u64, data: &Vec<u8>) -> Option<u8> {
//
//    }
}

fn swap_when_larger(atomic: &AtomicU64, value: u64) {
    let mut orig_num = atomic.load(ORDERING);
    loop {
        if orig_num >= value {
            return;
        }
        let actual = atomic.compare_and_swap(orig_num, value, ORDERING);
        if actual == orig_num {
            return;
        } else {
            orig_num = actual;
        }
    }
}<|endoftext|>


<commit_before>use std::cell::Cell;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering, fence};

use alloc;
use consume::CONSUME;
use countedindex::{CountedIndex, Transaction};
use maybe_acquire::{MAYBE_ACQUIRE, maybe_acquire_fence};
use memory::MemoryManager;

#[derive(Clone, Copy)]
enum ReaderState {
    Single,
    Multi,
}

pub struct ReaderPos {
    pos_data: CountedIndex,
}

pub struct ReaderMeta {
    state: Cell<ReaderState>,
    num_consumers: AtomicUsize,
}

pub struct Reader {
    pos: *const ReaderPos,
    meta: *const ReaderMeta,
}

/// This represents the reader attempt at loading a transaction
/// It behaves similarly to a Transaction but has logic for single/multi
/// readers
struct ReadAttempt<'a> {
    linked: Transaction<'a>,
    reader: &'a Reader,
    state: ReaderState,
}

/// This holds the set of readers currently active.
/// This struct is held out of line from the cursor so it's easy to atomically replace it
struct ReaderGroup {
    readers: Vec<*const Reader>,
}

#[repr(C)]
pub struct ReadCursor {
    readers: AtomicPtr<ReaderGroup>,
}

impl<'a> ReadAttempt<'a> {
    #[inline(always)]
    pub fn get(&self) -> (isize, usize) {
        self.linked.get()
    }

    #[inline(always)]
    pub fn commit_attempt(self, by: u32, ord: Ordering) -> Option<ReadAttempt<'a>> {
        match self.state {
            ReaderState::Single => {
                self.linked.commit_direct(by, ord);
                None
            }
            ReaderState::Multi => {
                if unsafe { (*self.reader.meta).num_consumers.load(Ordering::Relaxed) } == 1 {
                    fence(Ordering::Acquire);
                    unsafe {
                        (*self.reader.meta).state.set(ReaderState::Single);
                    }
                    self.linked.commit_direct(by, ord);
                    None
                } else {
                    match self.linked.commit(by, ord) {
                        Some(transaction) => {
                            Some(ReadAttempt {
                                linked: transaction,
                                reader: self.reader,
                                state: ReaderState::Multi,
                            })
                        }
                        None => None,
                    }
                }
            }
        }
    }
}

impl Reader {
    #[inline(always)]
    pub fn load_attempt(&self, ord: Ordering) -> ReadAttempt {
        unsafe {
            ReadAttempt {
                linked: (*self.pos).pos_data.load_transaction(ord),
                reader: self,
                state: (*self.meta).state.get(),
            }
        }
    }

    pub fn dup_consumer(&self) {
        unsafe {
            if (*self.meta).num_consumers.fetch_add(1, Ordering::SeqCst) == 1 {
                (*self.meta).state.set(ReaderState::Multi);
            }
        }
    }

    pub fn remove_consumer(&self) -> usize {
        unsafe { (*self.meta).num_consumers.fetch_sub(1, Ordering::SeqCst) }
    }

    pub fn get_consumers(&self) -> usize {
        unsafe { (*self.meta).num_consumers.load(Ordering::Relaxed) }
    }
}

impl ReaderGroup {
    pub fn new() -> ReaderGroup {
        ReaderGroup { readers: Vec::new() }
    }

    /// Only safe to call from a consumer of the queue!
    pub unsafe fn add_reader(&self, raw: usize, wrap: u32) -> (*mut ReaderGroup, *mut Reader) {
        let new_reader = alloc::allocate(1);
        let new_meta = alloc::allocate(1);
        let new_group = alloc::allocate(1);
        let new_pos = alloc::allocate(1);
        ptr::write(new_pos, ReaderPos { pos_data: CountedIndex::from_usize(raw, wrap) });
        ptr::write(new_meta,
                   ReaderMeta {
                       state: Cell::new(ReaderState::Single),
                       num_consumers: AtomicUsize::new(1),
                   });
        ptr::write(new_reader,
                   Reader {
                       pos: new_pos,
                       meta: new_meta as *const ReaderMeta,
                   });
        let mut new_readers = self.readers.clone();
        new_readers.push(new_reader as *const Reader);
        ptr::write(new_group, ReaderGroup { readers: new_readers });
        (new_group, new_reader)
    }

    pub unsafe fn remove_reader(&self, reader: *const Reader) -> *mut ReaderGroup {
        let new_group = alloc::allocate(1);
        let mut new_readers = self.readers.clone();
        new_readers.retain(|pt| *pt != reader);
        ptr::write(new_group, ReaderGroup { readers: new_readers });
        new_group
    }

    pub fn get_max_diff(&self, cur_writer: usize) -> Option<u32> {
        let mut max_diff: usize = 0;
        unsafe {
            for reader_ptr in &self.readers {
                // If a reader has passed the writer during this function call
                // then what must have happened is that somebody else has completed this
                // written to the queue, and a reader has bypassed it. We should retry
                let rpos = (*(**reader_ptr).pos).pos_data.load_count(MAYBE_ACQUIRE);
                let diff = cur_writer.wrapping_sub(rpos);
                if diff > (1 << 30) {
                    return None;
                }
                max_diff = if diff > max_diff { diff } else { max_diff };
            }
        }
        maybe_acquire_fence();

        assert!(max_diff <= (1 << 30));
        Some(max_diff as u32)
    }
}

impl ReadCursor {
    pub fn new(wrap: u32) -> (ReadCursor, *const Reader) {
        let rg = ReaderGroup::new();
        unsafe {
            let (real_group, reader) = rg.add_reader(0, wrap);
            (ReadCursor { readers: AtomicPtr::new(real_group) }, reader)
        }
    }

    #[inline(always)]
    pub fn prefetch_metadata(&self) {
        unsafe {
            let rg = &*self.readers.load(CONSUME);
            let dummy_ptr: *const usize = mem::transmute(&rg.readers);
            ptr::read_volatile(dummy_ptr);
        }
    }

    pub fn get_max_diff(&self, cur_writer: usize) -> Option<u32> {
        loop {
            unsafe {
                let first_ptr = self.readers.load(CONSUME);
                let rg = &*first_ptr;
                let rval = rg.get_max_diff(cur_writer);
                // This check ensures that the pointer hasn't changed
                // We must first read the diff, *and then* check the pointer
                // for changes. This is extremely similar to the seqlock except
                // with the pointer as the sequence lock instead of a different int
                //
                // We don't need another acquire fence here since the
                // relevant loads in get_max_diff are going to ordered
                // before all loads after the function exit, and also
                // ordered after the original pointer load
                let second_ptr = self.readers.load(MAYBE_ACQUIRE);
                if second_ptr == first_ptr {
                    maybe_acquire_fence();
                    return rval;
                }
            }
        }
    }

    // There's no fundamental reason these need to leak,
    // I just haven't implemented the memory management yet.
    // It's not too hard since we can track readers and writers active
    pub fn add_reader(&self, reader: &Reader, manager: &MemoryManager) -> *const Reader {
        let mut current_ptr = self.readers.load(CONSUME);
        loop {
            unsafe {
                let current_group = &*current_ptr;
                let raw = (*reader.pos).pos_data.load_raw(Ordering::Relaxed);
                let wrap = (*reader.pos).pos_data.wrap_at();
                let (new_group, new_reader) = current_group.add_reader(raw, wrap);
                match self.readers
                    .compare_exchange(current_ptr, new_group, Ordering::SeqCst, Ordering::SeqCst) {
                    Ok(_) => {
                        fence(Ordering::SeqCst);
                        manager.free(current_ptr, 1);
                        return new_reader as *const Reader;
                    }
                    Err(val) => {
                        current_ptr = val;
                        ptr::read(new_group);
                        alloc::deallocate((*new_reader).meta as *mut ReaderMeta, 1);
                        alloc::deallocate((*new_reader).pos as *mut ReaderPos, 1);
                        alloc::deallocate(new_group, 1);
                        alloc::deallocate(new_reader, 1);
                    }
                }
            }
        }
    }

    pub fn remove_reader(&self, reader: &Reader, mem: &MemoryManager) {
        let mut current_group = self.readers.load(CONSUME);
        loop {
            unsafe {
                let new_group = (*current_group).remove_reader(reader);
                match self.readers
                    .compare_exchange(current_group,
                                      new_group,
                                      Ordering::SeqCst,
                                      Ordering::SeqCst) {
                    Ok(_) => {
                        fence(Ordering::SeqCst);
                        mem.free(current_group, 1);
                        mem.free(reader.pos as *mut ReaderPos, 1);
                        alloc::deallocate(reader.meta as *mut ReaderMeta, 1);
                        break;
                    }
                    Err(val) => {
                        current_group = val;
                        ptr::read(new_group);
                        alloc::deallocate(new_group, 1);
                    }
                }
            }
        }
    }
}
<commit_msg>Pos now a ptr<commit_after>use std::cell::Cell;
use std::mem;
use std::ptr;
use std::sync::atomic::{AtomicPtr, AtomicUsize, Ordering, fence};

use alloc;
use consume::CONSUME;
use countedindex::{CountedIndex, Transaction};
use maybe_acquire::{MAYBE_ACQUIRE, maybe_acquire_fence};
use memory::MemoryManager;

#[derive(Clone, Copy)]
enum ReaderState {
    Single,
    Multi,
}

pub struct ReaderPos {
    pos_data: CountedIndex,
}

pub struct ReaderMeta {
    state: Cell<ReaderState>,
    num_consumers: AtomicUsize,
}

pub struct Reader {
    pos: *const ReaderPos,
    meta: *const ReaderMeta,
}

/// This represents the reader attempt at loading a transaction
/// It behaves similarly to a Transaction but has logic for single/multi
/// readers
struct ReadAttempt<'a> {
    linked: Transaction<'a>,
    reader: &'a Reader,
    state: ReaderState,
}

/// This holds the set of readers currently active.
/// This struct is held out of line from the cursor so it's easy to atomically replace it
struct ReaderGroup {
    readers: Vec<*const ReaderPos>,
}

#[repr(C)]
pub struct ReadCursor {
    readers: AtomicPtr<ReaderGroup>,
}

impl<'a> ReadAttempt<'a> {
    #[inline(always)]
    pub fn get(&self) -> (isize, usize) {
        self.linked.get()
    }

    #[inline(always)]
    pub fn commit_attempt(self, by: u32, ord: Ordering) -> Option<ReadAttempt<'a>> {
        match self.state {
            ReaderState::Single => {
                self.linked.commit_direct(by, ord);
                None
            }
            ReaderState::Multi => {
                if unsafe { (*self.reader.meta).num_consumers.load(Ordering::Relaxed) } == 1 {
                    fence(Ordering::Acquire);
                    unsafe {
                        (*self.reader.meta).state.set(ReaderState::Single);
                    }
                    self.linked.commit_direct(by, ord);
                    None
                } else {
                    match self.linked.commit(by, ord) {
                        Some(transaction) => {
                            Some(ReadAttempt {
                                linked: transaction,
                                reader: self.reader,
                                state: ReaderState::Multi,
                            })
                        }
                        None => None,
                    }
                }
            }
        }
    }
}

impl Reader {
    #[inline(always)]
    pub fn load_attempt(&self, ord: Ordering) -> ReadAttempt {
        unsafe {
            ReadAttempt {
                linked: (*self.pos).pos_data.load_transaction(ord),
                reader: self,
                state: (*self.meta).state.get(),
            }
        }
    }

    pub fn dup_consumer(&self) {
        unsafe {
            if (*self.meta).num_consumers.fetch_add(1, Ordering::SeqCst) == 1 {
                (*self.meta).state.set(ReaderState::Multi);
            }
        }
    }

    pub fn remove_consumer(&self) -> usize {
        unsafe { (*self.meta).num_consumers.fetch_sub(1, Ordering::SeqCst) }
    }

    pub fn get_consumers(&self) -> usize {
        unsafe { (*self.meta).num_consumers.load(Ordering::Relaxed) }
    }
}

impl ReaderGroup {
    pub fn new() -> ReaderGroup {
        ReaderGroup { readers: Vec::new() }
    }

    /// Only safe to call from a consumer of the queue!
    pub unsafe fn add_reader(&self, raw: usize, wrap: u32) -> (*mut ReaderGroup, *mut Reader) {
        let new_reader = alloc::allocate(1);
        let new_meta = alloc::allocate(1);
        let new_group = alloc::allocate(1);
        let new_pos = alloc::allocate(1);
        ptr::write(new_pos, ReaderPos { pos_data: CountedIndex::from_usize(raw, wrap) });
        ptr::write(new_meta,
                   ReaderMeta {
                       state: Cell::new(ReaderState::Single),
                       num_consumers: AtomicUsize::new(1),
                   });
        ptr::write(new_reader,
                   Reader {
                       pos: new_pos,
                       meta: new_meta as *const ReaderMeta,
                   });
        let mut new_readers = self.readers.clone();
        new_readers.push(new_pos as *const ReaderPos);
        ptr::write(new_group, ReaderGroup { readers: new_readers });
        (new_group, new_reader)
    }

    pub unsafe fn remove_reader(&self, reader: *const ReaderPos) -> *mut ReaderGroup {
        let new_group = alloc::allocate(1);
        let mut new_readers = self.readers.clone();
        new_readers.retain(|pt| *pt != reader);
        ptr::write(new_group, ReaderGroup { readers: new_readers });
        new_group
    }

    pub fn get_max_diff(&self, cur_writer: usize) -> Option<u32> {
        let mut max_diff: usize = 0;
        unsafe {
            for reader_ptr in &self.readers {
                // If a reader has passed the writer during this function call
                // then what must have happened is that somebody else has completed this
                // written to the queue, and a reader has bypassed it. We should retry
                let rpos = (**reader_ptr).pos_data.load_count(MAYBE_ACQUIRE);
                let diff = cur_writer.wrapping_sub(rpos);
                if diff > (1 << 30) {
                    return None;
                }
                max_diff = if diff > max_diff { diff } else { max_diff };
            }
        }
        maybe_acquire_fence();

        assert!(max_diff <= (1 << 30));
        Some(max_diff as u32)
    }
}

impl ReadCursor {
    pub fn new(wrap: u32) -> (ReadCursor, *const Reader) {
        let rg = ReaderGroup::new();
        unsafe {
            let (real_group, reader) = rg.add_reader(0, wrap);
            (ReadCursor { readers: AtomicPtr::new(real_group) }, reader)
        }
    }

    #[inline(always)]
    pub fn prefetch_metadata(&self) {
        unsafe {
            let rg = &*self.readers.load(CONSUME);
            let dummy_ptr: *const usize = mem::transmute(&rg.readers);
            ptr::read_volatile(dummy_ptr);
        }
    }

    pub fn get_max_diff(&self, cur_writer: usize) -> Option<u32> {
        loop {
            unsafe {
                let first_ptr = self.readers.load(CONSUME);
                let rg = &*first_ptr;
                let rval = rg.get_max_diff(cur_writer);
                // This check ensures that the pointer hasn't changed
                // We must first read the diff, *and then* check the pointer
                // for changes. This is extremely similar to the seqlock except
                // with the pointer as the sequence lock instead of a different int
                //
                // We don't need another acquire fence here since the
                // relevant loads in get_max_diff are going to ordered
                // before all loads after the function exit, and also
                // ordered after the original pointer load
                let second_ptr = self.readers.load(MAYBE_ACQUIRE);
                if second_ptr == first_ptr {
                    maybe_acquire_fence();
                    return rval;
                }
            }
        }
    }

    // There's no fundamental reason these need to leak,
    // I just haven't implemented the memory management yet.
    // It's not too hard since we can track readers and writers active
    pub fn add_reader(&self, reader: &Reader, manager: &MemoryManager) -> *const Reader {
        let mut current_ptr = self.readers.load(CONSUME);
        loop {
            unsafe {
                let current_group = &*current_ptr;
                let raw = (*reader.pos).pos_data.load_raw(Ordering::Relaxed);
                let wrap = (*reader.pos).pos_data.wrap_at();
                let (new_group, new_reader) = current_group.add_reader(raw, wrap);
                match self.readers
                    .compare_exchange(current_ptr, new_group, Ordering::SeqCst, Ordering::SeqCst) {
                    Ok(_) => {
                        fence(Ordering::SeqCst);
                        manager.free(current_ptr, 1);
                        return new_reader as *const Reader;
                    }
                    Err(val) => {
                        current_ptr = val;
                        ptr::read(new_group);
                        alloc::deallocate((*new_reader).meta as *mut ReaderMeta, 1);
                        alloc::deallocate((*new_reader).pos as *mut ReaderPos, 1);
                        alloc::deallocate(new_group, 1);
                        alloc::deallocate(new_reader, 1);
                    }
                }
            }
        }
    }

    pub fn remove_reader(&self, reader: &Reader, mem: &MemoryManager) {
        let mut current_group = self.readers.load(CONSUME);
        loop {
            unsafe {
                let new_group = (*current_group).remove_reader(reader.pos);
                match self.readers
                    .compare_exchange(current_group,
                                      new_group,
                                      Ordering::SeqCst,
                                      Ordering::SeqCst) {
                    Ok(_) => {
                        fence(Ordering::SeqCst);
                        mem.free(current_group, 1);
                        mem.free(reader.pos as *mut ReaderPos, 1);
                        alloc::deallocate(reader.meta as *mut ReaderMeta, 1);
                        break;
                    }
                    Err(val) => {
                        current_group = val;
                        ptr::read(new_group);
                        alloc::deallocate(new_group, 1);
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use vector::Layer;
use utils::_string;
use vector::ogr;
use vector::geometry::Geometry;

pub struct Feature<'a> {
    _layer: &'a Layer<'a>,
    c_feature: *const (),
    geometry: Geometry,
}

impl<'a> Feature<'a> {
    pub unsafe fn _with_layer(layer: &'a Layer<'a>, c_feature: *const ()) -> Feature<'a> {
        return Feature{
            _layer: layer,
            c_feature: c_feature,
            geometry: Geometry::lazy_feature_geometry(),
        };
    }

    pub fn field(&self, name: &str) -> Option<FieldValue> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let field_id = unsafe { ogr::OGR_F_GetFieldIndex(self.c_feature, c_name.as_ptr()) };
        if field_id == -1 {
            return None;
        }
        let field_defn = unsafe { ogr::OGR_F_GetFieldDefnRef(self.c_feature, field_id) };
        let field_type = unsafe { ogr::OGR_Fld_GetType(field_defn) };
        return match field_type {
            ogr::OFT_STRING => {
                let rv = unsafe { ogr::OGR_F_GetFieldAsString(self.c_feature, field_id) };
                return Some(FieldValue::StringValue(_string(rv)));
            },
            ogr::OFT_REAL => {
                let rv = unsafe { ogr::OGR_F_GetFieldAsDouble(self.c_feature, field_id) };
                return Some(FieldValue::RealValue(rv as f64));
            },
            _ => panic!("Unknown field type {}", field_type)
        }
    }

    pub fn geometry(&self) -> &Geometry {
        if ! self.geometry.has_gdal_ptr() {
            let c_geom = unsafe { ogr::OGR_F_GetGeometryRef(self.c_feature) };
            unsafe { self.geometry.set_c_geometry(c_geom) };
        }
        return &self.geometry;
    }

    pub fn wkt(&self) -> String {
        return self.geometry().wkt();
    }

    pub fn json(&self) -> String {
        return self.geometry().json();
    }
}

impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { ogr::OGR_F_Destroy(self.c_feature); }
    }
}

pub enum FieldValue {
    StringValue(String),
    RealValue(f64),
}

impl FieldValue {
    pub fn as_string(self) -> String {
        match self {
            FieldValue::StringValue(rv) => rv,
            _ => panic!("not a StringValue")
        }
    }

    pub fn as_real(self) -> f64 {
        match self {
            FieldValue::RealValue(rv) => rv,
            _ => panic!("not a RealValue")
        }
    }
}
<commit_msg>docs for `Feature`<commit_after>use std::ffi::CString;
use vector::Layer;
use utils::_string;
use vector::ogr;
use vector::geometry::Geometry;

/// OGR Feature
pub struct Feature<'a> {
    _layer: &'a Layer<'a>,
    c_feature: *const (),
    geometry: Geometry,
}

impl<'a> Feature<'a> {
    pub unsafe fn _with_layer(layer: &'a Layer<'a>, c_feature: *const ()) -> Feature<'a> {
        return Feature{
            _layer: layer,
            c_feature: c_feature,
            geometry: Geometry::lazy_feature_geometry(),
        };
    }

    /// Get the value of a named field. If the field exists, it returns a
    /// `FieldValue` wrapper, that you need to unpack to a base type
    /// (string, float, etc). If the field is missing, returns `None`.
    pub fn field(&self, name: &str) -> Option<FieldValue> {
        let c_name = CString::new(name.as_bytes()).unwrap();
        let field_id = unsafe { ogr::OGR_F_GetFieldIndex(self.c_feature, c_name.as_ptr()) };
        if field_id == -1 {
            return None;
        }
        let field_defn = unsafe { ogr::OGR_F_GetFieldDefnRef(self.c_feature, field_id) };
        let field_type = unsafe { ogr::OGR_Fld_GetType(field_defn) };
        return match field_type {
            ogr::OFT_STRING => {
                let rv = unsafe { ogr::OGR_F_GetFieldAsString(self.c_feature, field_id) };
                return Some(FieldValue::StringValue(_string(rv)));
            },
            ogr::OFT_REAL => {
                let rv = unsafe { ogr::OGR_F_GetFieldAsDouble(self.c_feature, field_id) };
                return Some(FieldValue::RealValue(rv as f64));
            },
            _ => panic!("Unknown field type {}", field_type)
        }
    }

    /// Get the field's geometry.
    pub fn geometry(&self) -> &Geometry {
        if ! self.geometry.has_gdal_ptr() {
            let c_geom = unsafe { ogr::OGR_F_GetGeometryRef(self.c_feature) };
            unsafe { self.geometry.set_c_geometry(c_geom) };
        }
        return &self.geometry;
    }

    pub fn wkt(&self) -> String {
        return self.geometry().wkt();
    }

    pub fn json(&self) -> String {
        return self.geometry().json();
    }
}

impl<'a> Drop for Feature<'a> {
    fn drop(&mut self) {
        unsafe { ogr::OGR_F_Destroy(self.c_feature); }
    }
}

pub enum FieldValue {
    StringValue(String),
    RealValue(f64),
}

impl FieldValue {
    /// Interpret the value as `String`. Panics if the value is something else.
    pub fn as_string(self) -> String {
        match self {
            FieldValue::StringValue(rv) => rv,
            _ => panic!("not a StringValue")
        }
    }

    /// Interpret the value as `f64`. Panics if the value is something else.
    pub fn as_real(self) -> f64 {
        match self {
            FieldValue::RealValue(rv) => rv,
            _ => panic!("not a RealValue")
        }
    }
}
<|endoftext|>


<commit_before>import azure::cairo;
import azure::cairo::bindgen::*;

fn on_main(f: fn~()) {
    let builder = task::builder();
    let opts = {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    };
    task::set_opts(builder, opts);
    task::run(builder, f);
}

fn main() {
    on_main {||
        sdl::init([
            sdl::init_video
        ]);
        let screen = sdl::video::set_video_mode(
            320, 200, 32,
            [sdl::video::swsurface],
            [sdl::video::doublebuf]);
        assert ptr::is_not_null(screen);
        let sdl_surf = sdl::video::create_rgb_surface(
            [sdl::video::swsurface],
            320, 200, 32,
            0x00FF0000u32,
            0x0000FF00u32,
            0x000000FFu32,
            0x00000000u32
            );
        assert ptr::is_not_null(sdl_surf);
        let cairo_surf = unsafe {
            cairo_image_surface_create_for_data(
                unsafe::reinterpret_cast((*sdl_surf).pixels),
                cairo::CAIRO_FORMAT_RGB24,
                (*sdl_surf).w,
                (*sdl_surf).h,
                (*sdl_surf).pitch as libc::c_int
            )
        };
        loop {
            sdl::video::blit_surface(sdl_surf, ptr::null(),
                                     screen, ptr::null());
            sdl::video::flip(screen);
            sdl::event::poll_event {|_event|
            }
        }
        cairo_surface_destroy(cairo_surf);
        sdl::quit();
    }
}<commit_msg>Create an azure target for the cairo/sdl surface. Doesn't seem to work<commit_after>import azure::bindgen::*;
import azure::cairo;
import azure::cairo::bindgen::*;

fn on_main(f: fn~()) {
    let builder = task::builder();
    let opts = {
        sched: some({
            mode: task::osmain,
            native_stack_size: none
        })
        with task::get_opts(builder)
    };
    task::set_opts(builder, opts);
    task::run(builder, f);
}

fn main() {
    on_main {||
        sdl::init([
            sdl::init_video
        ]);
        let screen = sdl::video::set_video_mode(
            320, 200, 32,
            [sdl::video::swsurface],
            [sdl::video::doublebuf]);
        assert !screen.is_null();
        let sdl_surf = sdl::video::create_rgb_surface(
            [sdl::video::swsurface],
            320, 200, 32,
            0x00FF0000u32,
            0x0000FF00u32,
            0x000000FFu32,
            0x00000000u32
            );
        assert !sdl_surf.is_null();
        let cairo_surf = unsafe {
            cairo_image_surface_create_for_data(
                unsafe::reinterpret_cast((*sdl_surf).pixels),
                cairo::CAIRO_FORMAT_RGB24,
                (*sdl_surf).w,
                (*sdl_surf).h,
                (*sdl_surf).pitch as libc::c_int
            )
        };
        assert !cairo_surf.is_null();
        let azure_target = CreateDrawTargetForCairoSurface(cairo_surf);
        assert !azure_target.is_null();

        loop {
            let rect = {
                x: 200f as azure::Float,
                y: 200f as azure::Float,
                width: 100f as azure::Float,
                height: 100f as azure::Float
            };
            let color = {
                r: 0f as azure::Float,
                g: 1f as azure::Float,
                b: 0f as azure::Float,
                a: 1f as azure::Float
            };
            let pattern = CreateColorPattern(ptr::addr_of(color));
            DrawTargetFillRect(
                azure_target,
                ptr::addr_of(rect),
                unsafe { unsafe::reinterpret_cast(pattern) });
            ReleaseColorPattern(pattern);

            sdl::video::blit_surface(sdl_surf, ptr::null(),
                                     screen, ptr::null());
            sdl::video::flip(screen);
            sdl::event::poll_event {|_event|
            }
        }
        ReleaseDrawTarget(azure_target);
        cairo_surface_destroy(cairo_surf);
        sdl::quit();
    }
}<|endoftext|>


<commit_before>#![crate_id = "github.com/csherratt/snowmew#snowmew:0.1"]
#![license = "ASL2"]
#![crate_type = "lib"]
#![comment = "A game engine in rust"]

#![feature(macro_rules)]
#![feature(globs)]
#![allow(experimental)]

extern crate semver;
extern crate std;
extern crate time;
extern crate glfw;
extern crate cgmath;
extern crate cow;
extern crate sync;
extern crate native;
extern crate std;
extern crate gl;
extern crate green;
extern crate collections;
extern crate libc;
extern crate OpenCL;
extern crate ovr = "oculus-vr";

pub use common::{ObjectKey};

use sync::Arc;
use OpenCL::hl::{Device, get_platforms, GPU, CPU};
use std::io::timer::Timer;

pub mod common;
pub mod camera;
pub mod io;

fn get_cl() -> Option<Arc<Device>> {
    let platforms = get_platforms();

    // find a gpu
    for platform in platforms.iter() {
        let devices = platform.get_devices_by_types(&[GPU]);
        if devices.len() != 0 {
            return Some(Arc::new(*devices.get(0)));
        }
    }

    // use cpu if no gpu was found
    for platform in platforms.iter() {
        let devices = platform.get_devices_by_types(&[CPU, GPU]);
        if devices.len() != 0 {
            return Some(Arc::new(*devices.get(0)));
        }
    }

    None
}

fn setup_glfw() -> glfw::Glfw {
    let glfw = glfw::init(glfw::LOG_ERRORS).ok().unwrap();

    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::Visible(false));
    glfw.window_hint(glfw::DepthBits(24));
    glfw.window_hint(glfw::StencilBits(8));
    glfw.window_hint(glfw::Decorated(false));

    glfw
}

pub fn start_manual_input(f: proc(&mut io::IOManager)) {
    let glfw = setup_glfw();

    let f = f;
    let mut im = io::IOManager::new(glfw);
    f(&mut im);
    println!("done");
}

pub struct DisplayConfig {
    pub resolution: Option<(u32, u32)>,
    pub position: Option<(i32, i32)>,
    pub hmd: bool,
    pub window: bool,
}

impl DisplayConfig {
    fn create_display(&self, im: &mut io::IOManager) -> Option<io::Window> {
        let window = if self.hmd { im.hmd() } else { None };
        if window.is_some() {
            return window;
        }

        let resolution = match self.resolution {
            Some(res) => res,
            None => im.get_primary_resolution()
        };

        let position = match self.position {
            Some(pos) => pos,
            None => im.get_primary_position()
        };

        if self.window {
            im.primary(resolution)
        } else {
            let win = im.window(resolution);
            match win {
                Some(win) => {
                    im.set_window_position(&win, position);
                    Some(win)
                }
                None => None
            }
        }
    }
}

pub trait Render<T> {
    fn update(&mut self, db: T, scene: ObjectKey, camera: ObjectKey);
}

pub trait RenderFactory<T, R: Render<T>> {
    fn init(self, window: io::Window, size: (i32, i32), cl: Option<Arc<Device>>) -> R;
}

pub struct SnowmewConfig<GD, R> {
    pub display: DisplayConfig,
    pub use_opencl: bool,
    pub cadance_ms: u64,
    pub render: Option<R>
}

impl<GD: Clone, R: Render<GD>, RF: RenderFactory<GD, R>> SnowmewConfig<GD, RF> {
    pub fn new() -> SnowmewConfig<GD, RF> {
        SnowmewConfig {
            display: DisplayConfig {
                resolution: None,
                position: None,
                hmd: true,
                window: true,
            },
            use_opencl: true,
            cadance_ms: 8,
            render: None
        }
    }

    pub fn start(self, gd: GD, game: |GD, &io::InputState, &io::InputState| -> (GD, ObjectKey, ObjectKey)) {
        let mut gd = gd;
        let mut im = io::IOManager::new(setup_glfw());

        // create display
        let display = match self.display.create_display(&mut im) {
            None => return,
            Some(display) => display
        };
        let ih = display.handle();

        let res = im.get_framebuffer_size(&display);
        let dev = if self.use_opencl { get_cl() } else { None };
        let mut render = self.render.unwrap().init(display, res, dev);

        let mut timer = Timer::new().unwrap();
        let timer_port = timer.periodic(self.cadance_ms);

        let mut input_last = im.get(&ih);
        while !input_last.should_close() {
            timer_port.recv();
            im.poll();
            let input = im.get(&ih);
            let (new_gd, scene, camera) = game(gd, &input, &input_last);
            render.update(new_gd.clone(), scene, camera);
            gd = new_gd;
            input_last = input;
        }
    }
}

<commit_msg>Fixed inverted boolean<commit_after>#![crate_id = "github.com/csherratt/snowmew#snowmew:0.1"]
#![license = "ASL2"]
#![crate_type = "lib"]
#![comment = "A game engine in rust"]

#![feature(macro_rules)]
#![feature(globs)]
#![allow(experimental)]

extern crate semver;
extern crate std;
extern crate time;
extern crate glfw;
extern crate cgmath;
extern crate cow;
extern crate sync;
extern crate native;
extern crate std;
extern crate gl;
extern crate green;
extern crate collections;
extern crate libc;
extern crate OpenCL;
extern crate ovr = "oculus-vr";

pub use common::{ObjectKey};

use sync::Arc;
use OpenCL::hl::{Device, get_platforms, GPU, CPU};
use std::io::timer::Timer;

pub mod common;
pub mod camera;
pub mod io;

fn get_cl() -> Option<Arc<Device>> {
    let platforms = get_platforms();

    // find a gpu
    for platform in platforms.iter() {
        let devices = platform.get_devices_by_types(&[GPU]);
        if devices.len() != 0 {
            return Some(Arc::new(*devices.get(0)));
        }
    }

    // use cpu if no gpu was found
    for platform in platforms.iter() {
        let devices = platform.get_devices_by_types(&[CPU, GPU]);
        if devices.len() != 0 {
            return Some(Arc::new(*devices.get(0)));
        }
    }

    None
}

fn setup_glfw() -> glfw::Glfw {
    let glfw = glfw::init(glfw::LOG_ERRORS).ok().unwrap();

    glfw.window_hint(glfw::OpenglProfile(glfw::OpenGlCoreProfile));
    glfw.window_hint(glfw::OpenglForwardCompat(true));
    glfw.window_hint(glfw::Visible(false));
    glfw.window_hint(glfw::DepthBits(24));
    glfw.window_hint(glfw::StencilBits(8));
    glfw.window_hint(glfw::Decorated(false));

    glfw
}

pub fn start_manual_input(f: proc(&mut io::IOManager)) {
    let glfw = setup_glfw();

    let f = f;
    let mut im = io::IOManager::new(glfw);
    f(&mut im);
    println!("done");
}

pub struct DisplayConfig {
    pub resolution: Option<(u32, u32)>,
    pub position: Option<(i32, i32)>,
    pub hmd: bool,
    pub window: bool,
}

impl DisplayConfig {
    fn create_display(&self, im: &mut io::IOManager) -> Option<io::Window> {
        let window = if self.hmd { im.hmd() } else { None };
        if window.is_some() {
            return window;
        }

        let resolution = match self.resolution {
            Some(res) => res,
            None => im.get_primary_resolution()
        };

        let position = match self.position {
            Some(pos) => pos,
            None => im.get_primary_position()
        };

        if !self.window {
            im.primary(resolution)
        } else {
            let win = im.window(resolution);
            match win {
                Some(win) => {
                    im.set_window_position(&win, position);
                    Some(win)
                }
                None => None
            }
        }
    }
}

pub trait Render<T> {
    fn update(&mut self, db: T, scene: ObjectKey, camera: ObjectKey);
}

pub trait RenderFactory<T, R: Render<T>> {
    fn init(self, window: io::Window, size: (i32, i32), cl: Option<Arc<Device>>) -> R;
}

pub struct SnowmewConfig<GD, R> {
    pub display: DisplayConfig,
    pub use_opencl: bool,
    pub cadance_ms: u64,
    pub render: Option<R>
}

impl<GD: Clone, R: Render<GD>, RF: RenderFactory<GD, R>> SnowmewConfig<GD, RF> {
    pub fn new() -> SnowmewConfig<GD, RF> {
        SnowmewConfig {
            display: DisplayConfig {
                resolution: None,
                position: None,
                hmd: true,
                window: true,
            },
            use_opencl: true,
            cadance_ms: 8,
            render: None
        }
    }

    pub fn start(self, gd: GD, game: |GD, &io::InputState, &io::InputState| -> (GD, ObjectKey, ObjectKey)) {
        let mut gd = gd;
        let mut im = io::IOManager::new(setup_glfw());

        // create display
        let display = match self.display.create_display(&mut im) {
            None => return,
            Some(display) => display
        };
        let ih = display.handle();

        let res = im.get_framebuffer_size(&display);
        let dev = if self.use_opencl { get_cl() } else { None };
        let mut render = self.render.unwrap().init(display, res, dev);

        let mut timer = Timer::new().unwrap();
        let timer_port = timer.periodic(self.cadance_ms);

        let mut input_last = im.get(&ih);
        while !input_last.should_close() {
            timer_port.recv();
            im.poll();
            let input = im.get(&ih);
            let (new_gd, scene, camera) = game(gd, &input, &input_last);
            render.update(new_gd.clone(), scene, camera);
            gd = new_gd;
            input_last = input;
        }
    }
}

<|endoftext|>


<commit_before>#![feature(proc_macro_hygiene, decl_macro)]

use anyhow::Result;
use askama::Template;
use byteorder::{LittleEndian, ReadBytesExt};
use rocket::response::content::Html;
use rocket::{get, routes, State};
use rocket_contrib::serve::StaticFiles;
use serde::Deserialize;
use shared::Searcher;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, Read};

#[derive(Deserialize)]
struct Manifest {
    #[serde(rename = "codepoints.bin")]
    codepoints_bin: String,
    #[serde(rename = "names.txt")]
    names_txt: String,
    #[serde(rename = "search.js")]
    search_js: String,
    #[serde(rename = "search.css")]
    search_css: String,
}

impl Manifest {
    fn new() -> Result<Self> {
        Ok(serde_json::from_str(include_str!(
            "../static/manifest.json"
        ))?)
    }

    fn load_file(path: &str) -> io::Result<File> {
        let server_dir = env!("CARGO_MANIFEST_DIR");
        let path = server_dir.to_string() + path;

        File::open(path)
    }

    fn load_file_string(path: &str) -> io::Result<String> {
        let mut file = Manifest::load_file(path)?;

        let mut string = String::new();
        file.read_to_string(&mut string)?;

        Ok(string)
    }

    fn load_file_u32(path: &str) -> io::Result<Vec<u32>> {
        let mut file = Manifest::load_file(path)?;
        let len = file.metadata()?.len() as usize;

        assert_eq!(len % 4, 0);

        let mut buf = vec![0; len / 4];
        file.read_u32_into::<LittleEndian>(&mut buf)?;

        Ok(buf)
    }
}

#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate;

#[get("/")]
fn index() -> Result<Html<String>> {
    Ok(Html(IndexTemplate.render()?))
}

struct RenderedSearchResult<'a> {
    literal: char,
    name: &'a str,
}

impl<'a> RenderedSearchResult<'a> {
    fn new(pattern: &str, searcher: &'a Searcher, codepoints: &[u32]) -> Vec<Self> {
        let mut results = searcher.search_words(&pattern);
        results.truncate(100);

        let names = searcher.names();

        results
            .into_iter()
            .map(|result| {
                let index = result.index();
                let codepoint = codepoints[index];

                let literal = char::try_from(codepoint).unwrap();

                RenderedSearchResult {
                    literal,
                    name: &names[index],
                }
            })
            .collect()
    }
}

#[derive(Template)]
#[template(path = "search.html")]
struct SearchTemplate<'a> {
    results: Vec<RenderedSearchResult<'a>>,
    manifest: &'a Manifest,
}

#[get("/search?<pattern>")]
fn search(
    searcher: State<Searcher>,
    manifest: State<Manifest>,
    codepoints: State<Vec<u32>>,
    pattern: Option<String>,
) -> Result<Html<String>> {
    let results = pattern
        .map(|pat| RenderedSearchResult::new(&pat, &searcher, &codepoints))
        .unwrap_or_default();

    let template = SearchTemplate {
        results,
        manifest: &manifest,
    };

    Ok(Html(template.render()?))
}

fn main() -> Result<()> {
    let manifest = Manifest::new()?;
    let names = Manifest::load_file_string(&manifest.names_txt)?;
    let codepoints = Manifest::load_file_u32(&manifest.codepoints_bin)?;

    let searcher = Searcher::from_names(&names);

    const STATIC_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/static");
    let err = rocket::ignite()
        .manage(searcher)
        .manage(manifest)
        .manage(codepoints)
        .mount("/", routes![index, search])
        .mount("/static", StaticFiles::from(STATIC_DIR))
        .launch();

    Err(err.into())
}
<commit_msg>Load codepoints file as Vec<char><commit_after>#![feature(proc_macro_hygiene, decl_macro)]

use anyhow::Result;
use askama::Template;
use byteorder::{LittleEndian, ReadBytesExt};
use rocket::response::content::Html;
use rocket::{get, routes, State};
use rocket_contrib::serve::StaticFiles;
use serde::Deserialize;
use shared::Searcher;
use std::convert::TryFrom;
use std::fs::File;
use std::io::{self, Read};

#[derive(Deserialize)]
struct Manifest {
    #[serde(rename = "codepoints.bin")]
    codepoints_bin: String,
    #[serde(rename = "names.txt")]
    names_txt: String,
    #[serde(rename = "search.js")]
    search_js: String,
    #[serde(rename = "search.css")]
    search_css: String,
}

impl Manifest {
    fn new() -> Result<Self> {
        Ok(serde_json::from_str(include_str!(
            "../static/manifest.json"
        ))?)
    }

    fn load_file(path: &str) -> io::Result<File> {
        let server_dir = env!("CARGO_MANIFEST_DIR");
        let path = server_dir.to_string() + path;

        File::open(path)
    }

    fn load_file_string(path: &str) -> io::Result<String> {
        let mut file = Manifest::load_file(path)?;

        let mut string = String::new();
        file.read_to_string(&mut string)?;

        Ok(string)
    }

    fn load_file_chars(path: &str) -> Result<Vec<char>> {
        let mut file = Manifest::load_file(path)?;
        let len = file.metadata()?.len() as usize;

        assert_eq!(len % 4, 0);

        let mut buf = vec![0; len / 4];
        file.read_u32_into::<LittleEndian>(&mut buf)?;

        let chars = buf
            .into_iter()
            .map(char::try_from)
            .collect::<Result<_, _>>()?;

        Ok(chars)
    }
}

#[derive(Template)]
#[template(path = "index.html")]
struct IndexTemplate;

#[get("/")]
fn index() -> Result<Html<String>> {
    Ok(Html(IndexTemplate.render()?))
}

struct RenderedSearchResult<'a> {
    literal: char,
    name: &'a str,
}

impl<'a> RenderedSearchResult<'a> {
    fn new(pattern: &str, searcher: &'a Searcher, codepoints: &[u32]) -> Vec<Self> {
        let mut results = searcher.search_words(&pattern);
        results.truncate(100);

        let names = searcher.names();

        results
            .into_iter()
            .map(|result| {
                let index = result.index();
                let codepoint = codepoints[index];

                let literal = char::try_from(codepoint).unwrap();

                RenderedSearchResult {
                    literal,
                    name: &names[index],
                }
            })
            .collect()
    }
}

#[derive(Template)]
#[template(path = "search.html")]
struct SearchTemplate<'a> {
    results: Vec<RenderedSearchResult<'a>>,
    manifest: &'a Manifest,
}

#[get("/search?<pattern>")]
fn search(
    searcher: State<Searcher>,
    manifest: State<Manifest>,
    codepoints: State<Vec<u32>>,
    pattern: Option<String>,
) -> Result<Html<String>> {
    let results = pattern
        .map(|pat| RenderedSearchResult::new(&pat, &searcher, &codepoints))
        .unwrap_or_default();

    let template = SearchTemplate {
        results,
        manifest: &manifest,
    };

    Ok(Html(template.render()?))
}

fn main() -> Result<()> {
    let manifest = Manifest::new()?;
    let names = Manifest::load_file_string(&manifest.names_txt)?;
    let codepoints = Manifest::load_file_chars(&manifest.codepoints_bin)?;

    let searcher = Searcher::from_names(&names);

    const STATIC_DIR: &str = concat!(env!("CARGO_MANIFEST_DIR"), "/static");
    let err = rocket::ignite()
        .manage(searcher)
        .manage(manifest)
        .manage(codepoints)
        .mount("/", routes![index, search])
        .mount("/static", StaticFiles::from(STATIC_DIR))
        .launch();

    Err(err.into())
}
<|endoftext|>


<commit_before>use std::str;

pub fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

pub fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<commit_msg>Add comment<commit_after>use std::str;

pub fn format_duration(duration: uint) -> ~str {
    let (mut n, mut pos, modifier) = if duration < 1000 {
            (duration, 3, ~"s")
        } else if duration < 60 * 1000 {
            (duration / 100, 1, ~"s")
        } else if duration < 60 * 60 * 1000 {
            (duration / 6000, 1, ~"m")
        } else {
            (duration / 360000, 1, ~"h")
        };
    while pos > 0 && n % 10 == 0 {
        n /= 10;
        pos -= 1;
    }
    let int_part = (n / pow(10, pos)).to_str();
    let mut fract_part = str::with_capacity(pos + 1);
    if pos != 0 && n != 0 {
        fract_part.push_char('.');
        while pos > 0 {
            let digit = (n / pow(10, pos - 1)) % 10;
            fract_part.push_char((digit as u8 + '0' as u8) as char);
            pos -= 1;
        }
    }
    int_part + fract_part + modifier
}

// FIXME: Can we replace it with std::num::pow?
fn pow(n: uint, p: uint) -> uint {
    let mut num = 1;
    for _ in range(0, p) {
        num *= n;
    }
    num
}

pub fn format_bytes(mut bytes: uint) -> ~str {
    static modifiers: [&'static str, ..4] = ["G", "M", "K", ""];
    let mut i = modifiers.len() - 1;
    while bytes >= 1024 && i != 0 {
        bytes /= 1024;
        i -= 1;
    }
    bytes.to_str() + modifiers[i]
}

/*
 * Tests
 */
#[cfg(test)]
mod test {
    use super::{format_duration, format_bytes};

    #[test]
    fn test_format_duration() {
        assert_eq!(~"0s", format_duration(0));
        assert_eq!(~"0.009s", format_duration(9));
        assert_eq!(~"0.09s", format_duration(90));
        assert_eq!(~"0.9s", format_duration(900));
        assert_eq!(~"0.999s", format_duration(999));
        assert_eq!(~"1s", format_duration(1000));
        assert_eq!(~"1s", format_duration(1009));
        assert_eq!(~"1.4s", format_duration(1400));
        assert_eq!(~"1.6s", format_duration(1600));
        assert_eq!(~"59s", format_duration(59000));
        assert_eq!(~"1m", format_duration(60000));
        assert_eq!(~"1.5m", format_duration(90000));
        assert_eq!(~"1h", format_duration(60 * 60 * 1000));
        assert_eq!(~"1.5h", format_duration(90 * 60 * 1000));
        assert_eq!(~"10h", format_duration(10 * 60 * 60 * 1000));
    }

    #[test]
    fn test_format_bytes() {
        assert_eq!(~"0", format_bytes(0));
        assert_eq!(~"9", format_bytes(9));
        assert_eq!(~"90", format_bytes(90));
        assert_eq!(~"900", format_bytes(900));
        assert_eq!(~"1000", format_bytes(1000));
        assert_eq!(~"1K", format_bytes(1024));
        assert_eq!(~"2K", format_bytes(2048));
        assert_eq!(~"4K", format_bytes(4096));
        assert_eq!(~"1M", format_bytes(1024 * 1024));
        assert_eq!(~"1G", format_bytes(1024 * 1024 * 1024));
        assert_eq!(~"1024G", format_bytes(1024 * 1024 * 1024 * 1024));
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

extern crate native;
extern crate glfw;

use glfw::Context;
use std::task::task;

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {
    let (glfw, errors) = glfw::init().unwrap();
    glfw::fail_on_error(&errors);

    let (mut window, events) = glfw.create_window(300, 300, "Hello this is window", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_key_polling(true);

    let render_context = window.render_context();
    let (send, recv) = channel();

    let mut render_task = task().named("render task");
    let render_task_done = render_task.future_result();
    render_task.spawn(proc() { render_main(render_context, recv) });

    while !window.should_close() {
        glfw.poll_events();
        glfw::fail_on_error(&errors);
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }
    }

    // tell the render task to exit.
    send.send(());

    // wait for ack
    let _ = render_task_done.recv();
}

fn render_main(context: glfw::RenderContext, info: Receiver<()>) {
    context.make_context_current();
    loop {
        // are we done?
        if info.try_recv() == std::comm::Data(()) {
            break;
        }

        // do gl calls here

        context.swap_buffers();
    }

    // required on some platforms
    glfw::make_context_current(None);
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        }
        _ => {}
    }
}
<commit_msg>Clean up render_task example<commit_after>// Copyright 2014 The GLFW-RS Developers. For a full listing of the authors,
// refer to the AUTHORS file at the top-level directory of this distribution.
//
// 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.

//! Demonstrates how concurrent rendering can be achieved
//! through the use of `RenderContext`s.

extern crate native;
extern crate glfw;

use glfw::Context;
use std::task::task;

#[start]
fn start(argc: int, argv: **u8) -> int {
    native::start(argc, argv, main)
}

fn main() {
    let (glfw, errors) = glfw::init().unwrap();
    glfw::fail_on_error(&errors);

    let (mut window, events) = glfw.create_window(300, 300, "Hello this is window", glfw::Windowed)
        .expect("Failed to create GLFW window.");

    window.set_key_polling(true);

    let render_context = window.render_context();
    let (send, recv) = channel();

    let mut render_task = task().named("render task");
    let render_task_done = render_task.future_result();
    render_task.spawn(proc() {
        render(render_context, recv);
    });

    while !window.should_close() {
        glfw.poll_events();
        glfw::fail_on_error(&errors);
        for (_, event) in glfw::flush_messages(&events) {
            handle_window_event(&window, event);
        }
    }

    // Tell the render task to exit.
    send.send(());

    // Wait for acknowledgement that the rendering was completed.
    let _ = render_task_done.recv();
}

fn render(context: glfw::RenderContext, finish: Receiver<()>) {
    context.make_context_current();
    loop {
        // Check if the rendering should stop.
        if finish.try_recv() == std::comm::Data(()) { break };

        // Perform rendering calls

        context.swap_buffers();
    }

    // required on some platforms
    glfw::make_context_current(None);
}

fn handle_window_event(window: &glfw::Window, event: glfw::WindowEvent) {
    match event {
        glfw::KeyEvent(glfw::KeyEscape, _, glfw::Press, _) => {
            window.set_should_close(true)
        }
        _ => {}
    }
}
<|endoftext|>


<commit_before>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Suffix" => suffixOutput( node ),
    "Prefix" => prefixOutput( node ),
    "Primary" => primaryOutput( node ),
    "DOT" => ~"base::Dot",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn wrapNodeOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNode( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNode( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  }
}

fn suffixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let macro_name = match children.get( 1 ).name {
      "QUESTION" => ~"opt",
      "STAR" => ~"star",
      "PLUS" => ~"plus",
      _ => fail!( "Bad second child." )
    };

    [ macro_name, ~"!( ", codeForNode( children.get( 0 ) ), ~" )" ].concat()
  }
}

fn prefixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 {
    codeForNodeContents( node )
  } else {
    let macro_name = children.get( 0 ).name.chars()
      .map( |x| x.to_lowercase() ).collect();
    [ macro_name, ~"!( ", codeForNode( children.get( 1 ) ), ~" )" ].concat()
  }
}

fn primaryOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 && children.get( 0 ).name == "Identifier" {
    wrapNodeOutput( ~"ex!( ", children.get( 0 ), ~" )" )
  } else {
    codeForNodeContents( node )
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<commit_msg>Minor refactoring<commit_after>
use std::str;
use parser::{Node, Children, Data};

#[macro_escape]
mod macros;

// TODO: figure out how to write this as a function on Node; the borrow checker
// was extra painful the last time you tried.
macro_rules! node_children( ( $node:expr ) => ( {
  match $node.contents {
    Children( ref nodes ) => nodes,
    _ => fail!( "No children in node." )
  } } ) )

pub fn codeForNode( node: &Node ) -> ~str {
  match node.name {
    "Definition" => wrapChildrenOutput( ~"rule!( ", node, ~" )\n" ),
    "Expression" => expressionOutput( node ),
    "Sequence" => sequenceOutput( node ),
    "Literal" => literalOutput( node ),
    "Class" => classOutput( node ),
    "Suffix" => suffixOutput( node ),
    "Prefix" => prefixOutput( node ),
    "Primary" => primaryOutput( node ),
    "DOT" => ~"base::Dot",
    "LEFTARROW" => ~" <- ",
    "SLASH" => ~", ",
    "Spacing" => ~"",
    "EndOfLine" => ~"",
    "OPEN" => ~"",
    "CLOSE" => ~"",
    _ => codeForNodeContents( node )
  }
}

fn codeForNodeContents( node: &Node ) -> ~str {
  match node.contents {
    Children( ref children ) => {
      // TODO: use StrBuf here somehow when it's merged in
      children.iter().map( codeForNode ).collect::<Vec<~str>>().concat()
    }
    Data( data ) => str::from_utf8( data ).unwrap().to_owned(),
  }
}

fn wrapChildrenOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNodeContents( node ), after ].concat()
}

fn wrapNodeOutput( before: ~str, node: &Node, after: ~str ) -> ~str {
  [ before, codeForNode( node ), after ].concat()
}

fn expressionOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    wrapChildrenOutput( ~"or!( ", node , ~" )" )
  } else {
    codeForNodeContents( node )
  }
}

fn sequenceOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() > 1 {
    let mut output = StrBuf::from_str( "seq!( " );
    for i in range( 0, children.len() ) {
      output.push_str( codeForNode( children.get( i ) ) );
      if i != children.len() -1 {
        output.push_str( ", " );
      }
    }
    output.push_str( " )" );
    output.into_owned()
  } else {
    codeForNodeContents( node )
  }
}

fn suffixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = match children.get( 1 ).name {
      "QUESTION" => ~"opt",
      "STAR" => ~"star",
      "PLUS" => ~"plus",
      _ => fail!( "Bad second child." )
    };

    [ macro_name, ~"!( ", codeForNode( children.get( 0 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn prefixOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 2 {
    let macro_name = children.get( 0 ).name.chars()
      .map( |x| x.to_lowercase() ).collect();
    [ macro_name, ~"!( ", codeForNode( children.get( 1 ) ), ~" )" ].concat()
  } else {
    codeForNodeContents( node )
  }
}

fn primaryOutput( node: &Node ) -> ~str {
  let children = node_children!( node );
  if children.len() == 1 && children.get( 0 ).name == "Identifier" {
    wrapNodeOutput( ~"ex!( ", children.get( 0 ), ~" )" )
  } else {
    codeForNodeContents( node )
  }
}

fn literalOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "lit" )
}

fn classOutput( node: &Node ) -> ~str {
  stringBasedRule( node, "class" )
}

fn stringBasedRule( node: &Node, rule_name: &str ) -> ~str {
  // TODO: unescape chars
  let content = codeForNodeContents( node ).trim().to_owned();

  [ rule_name.to_owned(),
    ~"!( r\"",
    content.slice_chars( 1, content.len() - 1 ).replace( r#"""#, r#"\""# ),
    ~"\" )" ].concat()
}
<|endoftext|>