<commit_before>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;
extern crate collections;

use collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: String,
    methods: Vec<String>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[String]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert("d",|_, cfg| { cfg.decompress = true; });
        handlers.insert("block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
			let slice = arg.as_slice();
            if slice.starts_with("-") {
                match handlers.mut_iter().find(|&(&k,_)| slice.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(slice.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", arg.as_slice()),
                }
            }else {
                cfg.methods.push(arg.to_string());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |Box<Writer>, &Config|: 'static -> Box<io::Writer>,
    decode: |Box<Reader>, &Config|: 'static -> Box<io::Reader>,
    info: String,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<String,Pass> = HashMap::new();
    passes.insert("dummy".to_str(), Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: "pass-through".to_str(),
    });
    passes.insert("ari".to_str(), Pass {
        encode: |w,_c| {
            box ari::ByteEncoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box ari::ByteDecoder::new(r) as Box<Reader>
        },
        info: "Adaptive arithmetic byte coder".to_str(),
    });
    passes.insert("bwt".to_str(), Pass {
        encode: |w,c| {
            box bwt::Encoder::new(w, c.block_size) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::Decoder::new(r, true) as Box<Reader>
        },
        info: "Burrows-Wheeler Transformation".to_str(),
    });
    passes.insert("mtf".to_str(), Pass {
        encode: |w,_c| {
            box bwt::mtf::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::mtf::Decoder::new(r) as Box<Reader>
        },
        info: "Move-To-Front Transformation".to_str(),
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert("lz4".to_str(), Pass {
        encode: |w,_c| {
            box lz4::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            box lz4::Decoder::new(r) as Box<Reader>
        },
        info: "Ziv-Lempel derivative, focused at speed".to_str(),
    });

    let config = Config::query(os::args().as_slice());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn(input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_string()
        });
        let mut rsum: Box<Reader> = box input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(met.as_slice()).unwrap();
        }
        let mut wsum: Box<Writer> = box output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<commit_msg>Updating to master<commit_after>#![crate_id = "app"]
#![crate_type = "bin"]
#![deny(warnings, missing_doc)]
#![feature(macro_rules, phase)]

//! A rust-compress application that allows testing of implemented
//! algorithms and their combinations using a simple command line.
//! Example invocations:
//! echo -n "abracadabra" | ./app bwt | xxd
//! echo "banana" | ./app bwt | ./app -d

#[phase(syntax, link)] extern crate log;
extern crate compress;

use std::collections::HashMap;
use std::{io, os, str};
use compress::{bwt, lz4};
use compress::entropy::ari;

static MAGIC    : u32   = 0x73632172;   //=r!cs

struct Config {
    exe_name: String,
    methods: Vec<String>,
    block_size: uint,
    decompress: bool,
}

impl Config {
    fn query(args: &[String]) -> Config {
        let mut cfg = Config {
            exe_name: args[0].clone(),
            methods: Vec::new(),
            block_size: 1<<16,
            decompress: false,
        };
        let mut handlers: HashMap<&str,|&str, &mut Config|> = HashMap::new();
        handlers.insert("d",|_, cfg| { cfg.decompress = true; });
        handlers.insert("block",|b, cfg| {
            cfg.block_size = from_str(b).unwrap();
        });

        for arg in args.iter().skip(1) {
			let slice = arg.as_slice();
            if slice.starts_with("-") {
                match handlers.mut_iter().find(|&(&k,_)| slice.slice_from(1).starts_with(k)) {
                    Some((k,h)) => (*h)(slice.slice_from(1+k.len()), &mut cfg),
                    None => println!("Warning: unrecognized option: {}", arg.as_slice()),
                }
            }else {
                cfg.methods.push(arg.to_string());
            }
        }
        cfg
    }
}

struct Pass {
    encode: |Box<Writer>, &Config|: 'static -> Box<io::Writer>,
    decode: |Box<Reader>, &Config|: 'static -> Box<io::Reader>,
    info: String,
}

/// main entry point
pub fn main() {
    let mut passes: HashMap<String,Pass> = HashMap::new();
    passes.insert("dummy".to_str(), Pass {
        encode: |w,_| w,
        decode: |r,_| r,
        info: "pass-through".to_str(),
    });
    passes.insert("ari".to_str(), Pass {
        encode: |w,_c| {
            box ari::ByteEncoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box ari::ByteDecoder::new(r) as Box<Reader>
        },
        info: "Adaptive arithmetic byte coder".to_str(),
    });
    passes.insert("bwt".to_str(), Pass {
        encode: |w,c| {
            box bwt::Encoder::new(w, c.block_size) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::Decoder::new(r, true) as Box<Reader>
        },
        info: "Burrows-Wheeler Transformation".to_str(),
    });
    passes.insert("mtf".to_str(), Pass {
        encode: |w,_c| {
            box bwt::mtf::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| {
            box bwt::mtf::Decoder::new(r) as Box<Reader>
        },
        info: "Move-To-Front Transformation".to_str(),
    });
    /* // looks like we are missing the encoder implementation
    passes.insert(~"flate", Pass {
        encode: |w,_c| {
            ~flate::Encoder::new(w, true) as ~Writer
        },
        decode: |r,_c| {
            ~flate::Decoder::new(r, true) as ~Reader
        },
        info: ~"Standardized Ziv-Lempel + Huffman variant",
    });*/
    passes.insert("lz4".to_str(), Pass {
        encode: |w,_c| {
            box lz4::Encoder::new(w) as Box<Writer>
        },
        decode: |r,_c| { // LZ4 decoder seem to work
            box lz4::Decoder::new(r) as Box<Reader>
        },
        info: "Ziv-Lempel derivative, focused at speed".to_str(),
    });

    let config = Config::query(os::args().as_slice());
    let mut input = io::stdin();
    let mut output = io::stdout();
    if config.decompress {
        assert!(config.methods.is_empty(), "Decompression methods are set in stone");
        match input.read_le_u32() {
            Ok(magic) if magic != MAGIC => {
                error!("Input is not a rust-compress archive");
                return
            },
            Err(e) => {
                error!("Unable to read input: {}", e.to_str());
                return
            },
            _ => () //OK
        }
        let methods = Vec::from_fn(input.read_u8().unwrap() as uint, |_| {
            let len = input.read_u8().unwrap() as uint;
            let bytes = input.read_exact(len).unwrap();
            str::from_utf8(bytes.as_slice()).unwrap().to_string()
        });
        let mut rsum: Box<Reader> = box input;
        for met in methods.iter() {
            info!("Found pass {}", *met);
            match passes.find_mut(met) {
                Some(pa) => rsum = (pa.decode)(rsum, &config),
                None => fail!("Pass is not implemented"),
            }
        }
        io::util::copy(&mut rsum, &mut output).unwrap();
    }else if config.methods.is_empty() {
        println!("rust-compress test application");
        println!("Usage:");
        println!("\t{} <options> <method1> .. <methodN> <input >output", config.exe_name);
        println!("Options:");
        println!("\t-d (to decompress)");
        println!("\t-block<N> (BWT block size)");
        println!("Passes:");
        for (name,pa) in passes.iter() {
            println!("\t{} = {}", *name, pa.info);
        }
    }else {
        output.write_le_u32(MAGIC).unwrap();
        output.write_u8(config.methods.len() as u8).unwrap();
        for met in config.methods.iter() {
            output.write_u8(met.len() as u8).unwrap();
            output.write_str(met.as_slice()).unwrap();
        }
        let mut wsum: Box<Writer> = box output;
        for met in config.methods.iter() {
            match passes.find_mut(met) {
                Some(pa) => wsum = (pa.encode)(wsum, &config),
                None => fail!("Pass {} is not implemented", *met)
            }
        }
        io::util::copy(&mut input, &mut wsum).unwrap();
        wsum.flush().unwrap();
    }
}
<|endoftext|>


<commit_before>use serde_json::{Value, from_str};
use serde_json::error::Result as R;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

struct JsonHeaderParser<'a> {
    spec: &'a FileHeaderSpec,
}

impl<'a> FileHeaderParser<'a> for JsonHeaderParser<'a> {

    fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> {
        JsonHeaderParser {
            spec: spec
        }
    }

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if (string.is_some()) {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(v)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}
<commit_msg>Implement Serialization for FileHeaderData<commit_after>use serde_json::{Value, from_str};
use serde_json::error::Result as R;
use serde_json::Serializer;
use serde::ser::Serialize;
use serde::ser::Serializer as Ser;

use std::collections::HashMap;
use std::io::stdout;

use super::super::parser::{FileHeaderParser, ParserError};
use super::super::file::{FileHeaderSpec, FileHeaderData};

struct JsonHeaderParser<'a> {
    spec: &'a FileHeaderSpec,
}

impl<'a> FileHeaderParser<'a> for JsonHeaderParser<'a> {

    fn new(spec: &'a FileHeaderSpec) -> JsonHeaderParser<'a> {
        JsonHeaderParser {
            spec: spec
        }
    }

    fn read(&self, string: Option<String>)
        -> Result<FileHeaderData, ParserError>
    {
        if (string.is_some()) {
            let s = string.unwrap();
            debug!("Deserializing: {}", s);
            let fromstr : R<Value> = from_str(&s[..]);
            if let Ok(content) = fromstr {
                Ok(visit_json(&content))
            } else {
                Err(ParserError::short("Unknown JSON parser error", s.clone(), 0))
            }
        } else {
            Ok(FileHeaderData::Null)
        }
    }

    fn write(&self, data: &FileHeaderData) -> Result<String, ParserError> {
        let mut ser = Serializer::pretty(stdout());
        data.serialize(&mut ser);
        Ok(String::from(""))
    }

}

// TODO: This function must be able to return a parser error
fn visit_json(v: &Value) -> FileHeaderData {
    match v {
        &Value::Null             => FileHeaderData::Null,
        &Value::Bool(b)          => FileHeaderData::Bool(b),
        &Value::I64(i)           => FileHeaderData::Integer(i),
        &Value::U64(u)           => FileHeaderData::UInteger(u),
        &Value::F64(f)           => FileHeaderData::Float(f),
        &Value::String(ref s)        => FileHeaderData::Text(s.clone()),
        &Value::Array(ref vec)       => {
            FileHeaderData::Array {
                values: Box::new(vec.clone().into_iter().map(|i| visit_json(v)).collect())
            }
        },
        &Value::Object(ref btree)    => {
            FileHeaderData::Map{
                keys: btree.clone().iter().map(|(k, v)|
                    FileHeaderData::Key {
                        name: k.clone(),
                        value: Box::new(visit_json(v)),
                    }
                ).collect()
            }
        }
    }
}

impl Serialize for FileHeaderData {

    fn serialize<S>(&self, ser: &mut S) -> Result<(), S::Error>
        where S: Ser
    {
        match self {
            &FileHeaderData::Null               => {
                let o : Option<bool> = None;
                o.serialize(ser)
            },
            &FileHeaderData::Bool(ref b)            => b.serialize(ser),
            &FileHeaderData::Integer(ref i)         => i.serialize(ser),
            &FileHeaderData::UInteger(ref u)        => u.serialize(ser),
            &FileHeaderData::Float(ref f)           => f.serialize(ser),
            &FileHeaderData::Text(ref s)            => (&s[..]).serialize(ser),
            &FileHeaderData::Array{values: ref vs}  => vs.serialize(ser),
            &FileHeaderData::Map{keys: ref ks}      => ks.serialize(ser),
            &FileHeaderData::Key{name: ref n, value: ref v}   => {
                let mut hm = HashMap::new();
                hm.insert(n, v);
                hm.serialize(ser)
            }
        }
    }

}
<|endoftext|>


<commit_before>#![allow(dead_code)]

use std::mem;
use std::ptr;
use libc::{c_int, c_ulong};

use runtime::Class;
use {Id, Message};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
    static _NSConcreteStackBlock: Class;
}

pub type BlockInvoke<A, R> =
    unsafe extern fn(*mut Block<A, R>, ...) -> R;

pub type ConcreteBlockInvoke<A, R, C> =
    unsafe extern fn(*mut ConcreteBlock<A, R, C>, ...) -> R;

pub trait BlockArguments {
    fn call_block<R>(self, block: &Block<Self, R>) -> R;

    fn invoke_for_concrete_block<R, C: Clone>() -> ConcreteBlockInvoke<Self, R, C>;
}

macro_rules! block_args_impl(
    ($f:ident $(, $a:ident : $t:ident)*) => (
        impl<$($t),*> BlockArguments for ($($t,)*) {
            fn call_block<R>(self, block: &Block<($($t,)*), R>) -> R {
                let invoke: unsafe extern fn(*mut Block<($($t,)*), R> $(, $t)*) -> R = unsafe {
                    mem::transmute(block.invoke)
                };
                let ($($a,)*) = self;
                let block_ptr = block as *const _ as *mut _;
                unsafe {
                    invoke(block_ptr $(, $a)*)
                }
            }

            fn invoke_for_concrete_block<R, X: Clone>() ->
                    ConcreteBlockInvoke<($($t,)*), R, X> {
                unsafe extern fn $f<R, X: Clone $(, $t)*>(
                        block_ptr: *mut ConcreteBlock<($($t,)*), R, X>
                        $(, $a: $t)*) -> R {
                    let args = ($($a,)*);
                    let block = &*block_ptr;
                    (block.rust_invoke)(&block.context, args)
                }

                unsafe {
                    mem::transmute($f::<R, X $(, $t)*>)
                }
            }
        }
    );
);

block_args_impl!(concrete_block_invoke_args0);
block_args_impl!(concrete_block_invoke_args1, a: A);
block_args_impl!(concrete_block_invoke_args2, a: A, b: B);
block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[repr(C)]
pub struct Block<A: BlockArguments, R> {
    isa: *const Class,
    flags: c_int,
    _reserved: c_int,
    invoke: BlockInvoke<A, R>,
}

impl<A: BlockArguments, R> Block<A, R> {
    pub fn copy(&self) -> Id<Block<A, R>> {
        unsafe {
            let block = msg_send![self copy] as *mut Block<A, R>;
            Id::from_retained_ptr(block)
        }
    }

    pub fn call(&self, args: A) -> R {
        args.call_block(self)
    }
}

impl<A: BlockArguments, R> Message for Block<A, R> { }

#[repr(C)]
struct ConcreteBlock<A: BlockArguments, R, C: Clone> {
    base: Block<A, R>,
    descriptor: *const BlockDescriptor<ConcreteBlock<A, R, C>>,
    rust_invoke: fn (&C, A) -> R,
    context: C,
}

impl<A: BlockArguments, R, C: Clone> ConcreteBlock<A, R, C> {
    pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock<A, R, C> {
        let extern_invoke: ConcreteBlockInvoke<A, R, C> =
            BlockArguments::invoke_for_concrete_block();
        ConcreteBlock {
            base: Block {
                isa: &_NSConcreteStackBlock,
                // 1 << 25 = BLOCK_HAS_COPY_DISPOSE
                flags: 1 << 25,
                _reserved: 0,
                invoke: unsafe { mem::transmute(extern_invoke) },
            },
            // TODO: don't leak memory here
            descriptor: unsafe {
                mem::transmute(box BlockDescriptor::<A, R, C>::new())
            },
            rust_invoke: invoke,
            context: context,
        }
    }
}

impl<A: BlockArguments, R, C: Clone> Clone for ConcreteBlock<A, R, C> {
    fn clone(&self) -> ConcreteBlock<A, R, C> {
        ConcreteBlock::new(self.rust_invoke, self.context.clone())
    }
}

unsafe extern fn block_context_dispose<A: BlockArguments, R, C: Clone>(
        block: &mut ConcreteBlock<A, R, C>) {
    let mut context = mem::uninitialized();
    ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1);
    drop(context);
}

unsafe extern fn block_context_copy<A: BlockArguments, R, C: Clone>(
        dst: &mut ConcreteBlock<A, R, C>, src: &ConcreteBlock<A, R, C>) {
    dst.context = src.context.clone();
}

#[repr(C)]
struct BlockDescriptor<B> {
    _reserved: c_ulong,
    block_size: c_ulong,
    copy_helper: unsafe extern fn(&mut B, &B),
    dispose_helper: unsafe extern fn(&mut B),
}

impl<A: BlockArguments, R, C: Clone> BlockDescriptor<ConcreteBlock<A, R, C>> {
    pub fn new() -> BlockDescriptor<ConcreteBlock<A, R, C>> {
        BlockDescriptor {
            _reserved: 0,
            block_size: mem::size_of::<ConcreteBlock<A, R, C>>() as c_ulong,
            copy_helper: block_context_copy::<A, R, C>,
            dispose_helper: block_context_dispose::<A, R, C>,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use objc_test_utils::invoke_int_block;
    use super::ConcreteBlock;

    #[test]
    fn test_create_block() {
        fn block_get_int(context: &int, _args: ()) -> int {
            *context
        }

        let result = unsafe {
            let block = ConcreteBlock::new(block_get_int, 13i);
            invoke_int_block(mem::transmute(&block))
        };
        assert!(result == 13);
    }
}
<commit_msg>Implemented Deref to Block for ConcreteBlock.<commit_after>#![allow(dead_code)]

use std::mem;
use std::ptr;
use libc::{c_int, c_ulong};

use runtime::Class;
use {Id, Message};

#[allow(improper_ctypes)]
#[link(name = "Foundation", kind = "framework")]
extern {
    static _NSConcreteStackBlock: Class;
}

pub type BlockInvoke<A, R> =
    unsafe extern fn(*mut Block<A, R>, ...) -> R;

pub type ConcreteBlockInvoke<A, R, C> =
    unsafe extern fn(*mut ConcreteBlock<A, R, C>, ...) -> R;

pub trait BlockArguments {
    fn call_block<R>(self, block: &Block<Self, R>) -> R;

    fn invoke_for_concrete_block<R, C: Clone>() -> ConcreteBlockInvoke<Self, R, C>;
}

macro_rules! block_args_impl(
    ($f:ident $(, $a:ident : $t:ident)*) => (
        impl<$($t),*> BlockArguments for ($($t,)*) {
            fn call_block<R>(self, block: &Block<($($t,)*), R>) -> R {
                let invoke: unsafe extern fn(*mut Block<($($t,)*), R> $(, $t)*) -> R = unsafe {
                    mem::transmute(block.invoke)
                };
                let ($($a,)*) = self;
                let block_ptr = block as *const _ as *mut _;
                unsafe {
                    invoke(block_ptr $(, $a)*)
                }
            }

            fn invoke_for_concrete_block<R, X: Clone>() ->
                    ConcreteBlockInvoke<($($t,)*), R, X> {
                unsafe extern fn $f<R, X: Clone $(, $t)*>(
                        block_ptr: *mut ConcreteBlock<($($t,)*), R, X>
                        $(, $a: $t)*) -> R {
                    let args = ($($a,)*);
                    let block = &*block_ptr;
                    (block.rust_invoke)(&block.context, args)
                }

                unsafe {
                    mem::transmute($f::<R, X $(, $t)*>)
                }
            }
        }
    );
);

block_args_impl!(concrete_block_invoke_args0);
block_args_impl!(concrete_block_invoke_args1, a: A);
block_args_impl!(concrete_block_invoke_args2, a: A, b: B);
block_args_impl!(concrete_block_invoke_args3, a: A, b: B, c: C);
block_args_impl!(concrete_block_invoke_args4, a: A, b: B, c: C, d: D);
block_args_impl!(concrete_block_invoke_args5, a: A, b: B, c: C, d: D, e: E);
block_args_impl!(concrete_block_invoke_args6, a: A, b: B, c: C, d: D, e: E, f: F);
block_args_impl!(concrete_block_invoke_args7, a: A, b: B, c: C, d: D, e: E, f: F, g: G);
block_args_impl!(concrete_block_invoke_args8, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
block_args_impl!(concrete_block_invoke_args9, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
block_args_impl!(concrete_block_invoke_args10, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
block_args_impl!(concrete_block_invoke_args11, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
block_args_impl!(concrete_block_invoke_args12, a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[repr(C)]
pub struct Block<A: BlockArguments, R> {
    isa: *const Class,
    flags: c_int,
    _reserved: c_int,
    invoke: BlockInvoke<A, R>,
}

impl<A: BlockArguments, R> Block<A, R> {
    pub fn copy(&self) -> Id<Block<A, R>> {
        unsafe {
            let block = msg_send![self copy] as *mut Block<A, R>;
            Id::from_retained_ptr(block)
        }
    }

    pub fn call(&self, args: A) -> R {
        args.call_block(self)
    }
}

impl<A: BlockArguments, R> Message for Block<A, R> { }

#[repr(C)]
struct ConcreteBlock<A: BlockArguments, R, C: Clone> {
    base: Block<A, R>,
    descriptor: *const BlockDescriptor<ConcreteBlock<A, R, C>>,
    rust_invoke: fn (&C, A) -> R,
    context: C,
}

impl<A: BlockArguments, R, C: Clone> ConcreteBlock<A, R, C> {
    pub fn new(invoke: fn (&C, A) -> R, context: C) -> ConcreteBlock<A, R, C> {
        let extern_invoke: ConcreteBlockInvoke<A, R, C> =
            BlockArguments::invoke_for_concrete_block();
        ConcreteBlock {
            base: Block {
                isa: &_NSConcreteStackBlock,
                // 1 << 25 = BLOCK_HAS_COPY_DISPOSE
                flags: 1 << 25,
                _reserved: 0,
                invoke: unsafe { mem::transmute(extern_invoke) },
            },
            // TODO: don't leak memory here
            descriptor: unsafe {
                mem::transmute(box BlockDescriptor::<A, R, C>::new())
            },
            rust_invoke: invoke,
            context: context,
        }
    }
}

impl<A: BlockArguments, R, C: Clone> Clone for ConcreteBlock<A, R, C> {
    fn clone(&self) -> ConcreteBlock<A, R, C> {
        ConcreteBlock::new(self.rust_invoke, self.context.clone())
    }
}

impl<A: BlockArguments, R, C: Clone> Deref<Block<A, R>> for ConcreteBlock<A, R, C> {
    fn deref(&self) -> &Block<A, R> {
        &self.base
    }
}

unsafe extern fn block_context_dispose<A: BlockArguments, R, C: Clone>(
        block: &mut ConcreteBlock<A, R, C>) {
    let mut context = mem::uninitialized();
    ptr::copy_nonoverlapping_memory(&mut context, &block.context, 1);
    drop(context);
}

unsafe extern fn block_context_copy<A: BlockArguments, R, C: Clone>(
        dst: &mut ConcreteBlock<A, R, C>, src: &ConcreteBlock<A, R, C>) {
    dst.context = src.context.clone();
}

#[repr(C)]
struct BlockDescriptor<B> {
    _reserved: c_ulong,
    block_size: c_ulong,
    copy_helper: unsafe extern fn(&mut B, &B),
    dispose_helper: unsafe extern fn(&mut B),
}

impl<A: BlockArguments, R, C: Clone> BlockDescriptor<ConcreteBlock<A, R, C>> {
    pub fn new() -> BlockDescriptor<ConcreteBlock<A, R, C>> {
        BlockDescriptor {
            _reserved: 0,
            block_size: mem::size_of::<ConcreteBlock<A, R, C>>() as c_ulong,
            copy_helper: block_context_copy::<A, R, C>,
            dispose_helper: block_context_dispose::<A, R, C>,
        }
    }
}

#[cfg(test)]
mod tests {
    use std::mem;
    use objc_test_utils::invoke_int_block;
    use super::ConcreteBlock;

    #[test]
    fn test_create_block() {
        fn block_get_int(context: &int, _args: ()) -> int {
            *context
        }

        let result = unsafe {
            let block = ConcreteBlock::new(block_get_int, 13i);
            invoke_int_block(mem::transmute(&block))
        };
        assert!(result == 13);
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use std::collections::{HashMap, HashSet};

use crate::{type_database::TypeDatabase, types::TypeName};

use super::api::Api;

/// This is essentially mark-and-sweep garbage collection of the
/// Apis that we've discovered. Why do we do this, you might wonder?
/// It seems a bit strange given that we pass an explicit allowlist
/// to bindgen.
/// There are two circumstances under which we want to discard
/// some of the APIs we encounter parsing the bindgen.
/// 1) We simplify some struct to be non-POD. In this case, we'll
///    discard all the fields within it. Those fields can be, and
///    in fact often _are_, stuff which we have trouble converting
///    e.g. std::string or std::string::value_type or
///    my_derived_thing<std::basic_string::value_type> or some
///    other permutation. In such cases, we want to discard those
///    field types with prejudice.
/// 2) block! may be used to ban certain APIs. This often eliminates
///    some methods from a given struct/class. In which case, we
///    don't care about the other parameter types passed into those
///    APIs either.
pub(crate) fn filter_apis_by_following_edges_from_allowlist(
    mut apis: Vec<Api>,
    type_database: &TypeDatabase,
) -> Vec<Api> {
    let mut todos: Vec<_> = apis
        .iter()
        .filter(|api| {
            let tnforal = api.typename_for_allowlist();
            log::info!("Considering {}", tnforal);
            type_database.is_on_allowlist(&tnforal)
        })
        .map(Api::typename)
        .collect();
    let mut by_typename: HashMap<TypeName, Vec<Api>> = HashMap::new();
    for api in apis.drain(..) {
        let tn = api.typename();
        by_typename.entry(tn).or_default().push(api);
    }
    let mut done = HashSet::new();
    let mut output = Vec::new();
    while !todos.is_empty() {
        let todo = todos.remove(0);
        if done.contains(&todo) {
            continue;
        }
        if let Some(mut these_apis) = by_typename.remove(&todo) {
            todos.extend(these_apis.iter_mut().flat_map(|api| api.deps.drain()));
            output.append(&mut these_apis);
        } // otherwise, probably an intrinsic e.g. uint32_t.
        done.insert(todo);
    }
    output
}
<commit_msg>Remove excess logging.<commit_after>// Copyright 2020 Google LLC
//
// 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
//
//    https://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.

use std::collections::{HashMap, HashSet};

use crate::{type_database::TypeDatabase, types::TypeName};

use super::api::Api;

/// This is essentially mark-and-sweep garbage collection of the
/// Apis that we've discovered. Why do we do this, you might wonder?
/// It seems a bit strange given that we pass an explicit allowlist
/// to bindgen.
/// There are two circumstances under which we want to discard
/// some of the APIs we encounter parsing the bindgen.
/// 1) We simplify some struct to be non-POD. In this case, we'll
///    discard all the fields within it. Those fields can be, and
///    in fact often _are_, stuff which we have trouble converting
///    e.g. std::string or std::string::value_type or
///    my_derived_thing<std::basic_string::value_type> or some
///    other permutation. In such cases, we want to discard those
///    field types with prejudice.
/// 2) block! may be used to ban certain APIs. This often eliminates
///    some methods from a given struct/class. In which case, we
///    don't care about the other parameter types passed into those
///    APIs either.
pub(crate) fn filter_apis_by_following_edges_from_allowlist(
    mut apis: Vec<Api>,
    type_database: &TypeDatabase,
) -> Vec<Api> {
    let mut todos: Vec<_> = apis
        .iter()
        .filter(|api| {
            let tnforal = api.typename_for_allowlist();
            type_database.is_on_allowlist(&tnforal)
        })
        .map(Api::typename)
        .collect();
    let mut by_typename: HashMap<TypeName, Vec<Api>> = HashMap::new();
    for api in apis.drain(..) {
        let tn = api.typename();
        by_typename.entry(tn).or_default().push(api);
    }
    let mut done = HashSet::new();
    let mut output = Vec::new();
    while !todos.is_empty() {
        let todo = todos.remove(0);
        if done.contains(&todo) {
            continue;
        }
        if let Some(mut these_apis) = by_typename.remove(&todo) {
            todos.extend(these_apis.iter_mut().flat_map(|api| api.deps.drain()));
            output.append(&mut these_apis);
        } // otherwise, probably an intrinsic e.g. uint32_t.
        done.insert(todo);
    }
    output
}
<|endoftext|>


<commit_before>use std::fmt;
use std::mem;
use std::sync::Arc;
use std::net::SocketAddr;

use futures::Async;
use futures::future::{FutureResult, ok};
use tk_http::Status;
use tk_http::server::{Dispatcher, Error, Head};
use tk_http::server as http;
use tk_http::server::{EncoderDone, RecvMode};
use serde_json::{self, Value as Json};

use intern::{Topic, Lattice as Namespace};
use chat::cid::PubCid;
use chat::processor::Action;
use chat::processor::Delta;
use chat::listener::spawn::WorkerData;
use chat::replication::RemoteAction;

pub struct Handler {
    addr: SocketAddr,
    wdata: Arc<WorkerData>,
}

pub enum State {
    Query(Route),
    Done,
    Error(Status),
}

pub struct Request {
    wdata: Arc<WorkerData>,
    state: State,
}

pub enum Route {
    /// `PUT /v1/connection/<conn_id>/subscriptions/<path>`
    Subscribe(PubCid, Topic),
    /// `DELETE /v1/connection/<conn_id>/subscriptions/<path>`
    Unsubscribe(PubCid, Topic),
    /// `POST /v1/publish/<path>`
    Publish(Topic),
    /// `PUT /v1/connection/<conn_id>/lattices/<namespace>`
    LatticeSubscribe(PubCid, Namespace),
    /// `DELETE /v1/connection/<conn_id>/lattices/<namespace>`
    Detach(PubCid, Namespace),
    /// `POST /v1/lattice/<namespace>`
    Lattice(Namespace),
}

impl fmt::Display for Route {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Route::*;
        match *self {
            Subscribe(ref cid, ref tpc) => {
                write!(f, "Subscribe {:#?} {:?}", cid.0, tpc)
            }
            Unsubscribe(ref cid, ref tpc) => {
                write!(f, "Unsubscribe {:#?} {:?}", cid.0, tpc)
            }
            Publish(ref topic) => write!(f, "Publish {:?}", topic),
            LatticeSubscribe(ref cid, ref ns) => {
                write!(f, "Lattice subscribe {:#?} {:?}", cid.0, ns)
            }
            Detach(ref cid, ref ns) => {
                write!(f, "Lattice detach {:#?} {:?}", cid.0, ns)
            }
            Lattice(ref ns) => write!(f, "Lattice update {:?}", ns),
        }
    }
}

impl Handler {
    pub fn new(addr: SocketAddr, wdata: Arc<WorkerData>)
        -> Handler
    {
        Handler {
            addr: addr,
            wdata: wdata,
        }
    }
}

impl<S> Dispatcher<S> for Handler {
    type Codec = Request;
    fn headers_received(&mut self, headers: &Head)
        -> Result<Self::Codec, Error>
    {
        let query = match headers.path() {
            Some(path) => {
                if !path.starts_with("/v1/") {
                    State::Error(Status::NotFound)
                } else {
                    self.dispatch(&path[4..], headers.method())
                }
            }
            None => {
                State::Error(Status::BadRequest)
            }
        };
        match query {
            State::Query(ref route) => {
                info!("{:?} received {} (ip: {})",
                    self.wdata.name, route, self.addr);
            }
            State::Done => unreachable!(),
            State::Error(status) => {
                info!("{:?} path {:?} gets {:?} (ip: {})",
                    self.wdata.name, headers.path(), status, self.addr);
            }
        }
        Ok(Request {
            wdata: self.wdata.clone(),
            state: query,
        })
    }
}

impl Handler {
    fn dispatch(&mut self, path: &str, method: &str) -> State {
        let mut iter = path.splitn(2, '/');
        let head = iter.next().unwrap();
        let tail = iter.next();
        match (method, head, tail) {
            (_, "connection", Some(tail)) => {
                let mut p = tail.splitn(3, '/');
                let cid = p.next().and_then(|x| x.parse().ok());
                let middle = p.next();
                let tail = p.next();
                match middle {
                    Some("subscriptions") => {
                        let topic = tail.and_then(|x| {
                            if !x.contains('.') {
                                x.replace("/", ".").parse().ok()
                            } else {
                                None
                            }
                        });
                        match (method, cid, topic) {
                            ("PUT", Some(cid), Some(t)) => {
                                State::Query(Route::Subscribe(cid, t))
                            }
                            ("DELETE", Some(cid), Some(t)) => {
                                State::Query(Route::Unsubscribe(cid, t))
                            }
                            _ => State::Error(Status::NotFound),
                        }
                    }
                    Some("lattices") => {
                        let ns = tail.and_then(|x| {
                            if !x.contains('.') {
                                x.replace("/", ".").parse().ok()
                            } else {
                                None
                            }
                        });
                        match (method, cid, ns) {
                            ("PUT", Some(cid), Some(ns)) => {
                                State::Query(Route::LatticeSubscribe(cid, ns))
                            }
                            ("DELETE", Some(cid), Some(ns)) => {
                                State::Query(Route::Detach(cid, ns))
                            }
                            _ => State::Error(Status::NotFound),
                        }
                    }
                    _ => State::Error(Status::NotFound),
                }
            }
            ("POST", "publish", Some(tail)) => {
                let topic = if !tail.contains('.') {
                    tail.replace("/", ".").parse().ok()
                } else {
                    None
                };
                if let Some(topic) = topic {
                    State::Query(Route::Publish(topic))
                } else {
                    State::Error(Status::NotFound)
                }
            }
            ("POST", "lattice", Some(tail)) => {
                let ns = if !tail.contains('.') {
                    tail.replace("/", ".").parse().ok()
                } else {
                    None
                };
                if let Some(ns) = ns {
                    State::Query(Route::Lattice(ns))
                } else {
                    State::Error(Status::NotFound)
                }
            }
            _ => {
                State::Error(Status::NotFound)
            }
        }
    }
}

impl<S> http::Codec<S> for Request {
    type ResponseFuture = FutureResult<EncoderDone<S>, Error>;
    fn recv_mode(&mut self) -> RecvMode {
        RecvMode::buffered_upfront(self.wdata.settings.max_payload_size)
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        use self::Route::*;
        assert!(end);
        let my_srv_id = self.wdata.runtime.server_id;
        let query = mem::replace(&mut self.state,
                                 State::Error(Status::InternalServerError));
        self.state = match query {
            State::Query(Subscribe(PubCid(cid, srv_id), topic)) => {
                if data.len() == 0 {
                    if srv_id == my_srv_id {
                        self.wdata.processor.send(Action::Subscribe {
                            conn_id: cid,
                            topic: topic.clone(),
                        });
                    } else {
                        debug!("Skipping action with non-local cid");
                    }
                    self.wdata.remote.send(RemoteAction::Subscribe {
                        conn_id: cid,
                        server_id: srv_id,
                        topic: topic,
                    });
                    State::Done
                } else {
                    State::Error(Status::BadRequest)
                }
            }
            State::Query(Unsubscribe(PubCid(cid, srv_id), topic)) => {
                if data.len() == 0 {
                    if srv_id == my_srv_id {
                        self.wdata.remote.send(RemoteAction::Unsubscribe {
                            conn_id: cid,
                            server_id: srv_id,
                            topic: topic.clone(),
                        });
                    } else {
                        debug!("Skipping action with non-local cid");
                    }
                    self.wdata.processor.send(Action::Unsubscribe {
                        conn_id: cid,
                        topic: topic,
                    });
                    State::Done
                } else {
                    State::Error(Status::BadRequest)
                }
            }
            State::Query(Publish(topic)) => {
                // TODO(tailhook) check content-type
                match serde_json::from_slice(data) {
                    Ok(json) => {
                        // Send this Action to Replication Queue
                        let data: Arc<Json> = Arc::new(json);
                        self.wdata.remote.send(RemoteAction::Publish {
                            topic: topic.clone(),
                            data: data.clone(),
                        });
                        self.wdata.processor.send(Action::Publish {
                            topic: topic,
                            data: data,
                        });
                        State::Done
                    }
                    Err(e) => {
                        info!("Error decoding json for '/v1/publish': \
                            {:?}", e);
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Query(LatticeSubscribe(PubCid(cid, srv_id), ns)) => {
                // TODO(tailhook) check content-type
                let data: Result<Delta,_> = serde_json::from_slice(data)
                    .map_err(|e| {
                        info!("Error decoding json for \
                            '/v1/lattice/_/subscribe': \
                            {:?}", e);
                    });
                match data {
                    Ok(delta) => {
                        self.wdata.remote.send(RemoteAction::Lattice {
                            namespace: ns.clone(),
                            delta: delta.clone(),
                        });
                        self.wdata.remote.send(RemoteAction::Attach {
                            namespace: ns.clone(),
                            conn_id: cid,
                            server_id: srv_id,
                        });
                        self.wdata.processor.send(Action::Lattice {
                            namespace: ns.clone(),
                            delta: delta,
                        });
                        if srv_id == my_srv_id {
                            self.wdata.processor.send(Action::Attach {
                                namespace: ns.clone(),
                                conn_id: cid,
                            });
                        } else {
                            debug!("Skipping action with non-local cid");
                        }
                        State::Done
                    }
                    Err(_) => {
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Query(Detach(PubCid(cid, srv_id), ns)) => {
                self.wdata.remote.send(RemoteAction::Detach {
                    namespace: ns.clone(),
                    conn_id: cid.clone(),
                    server_id: srv_id,
                });
                if srv_id == my_srv_id {
                    self.wdata.processor.send(Action::Detach {
                        namespace: ns.clone(),
                        conn_id: cid,
                    });
                } else {
                    debug!("Skipping action with non-local cid");
                }
                State::Done
            }
            State::Query(Lattice(ns)) => {
                // TODO(tailhook) check content-type
                let data: Result<Delta,_> = serde_json::from_slice(data)
                    .map_err(|e| {
                        info!("Error decoding json for \
                            '/v1/lattice': \
                            {:?}", e);
                    });
                match data {
                    Ok(delta) => {
                        // Send this Action to Replication Queue
                        self.wdata.remote.send(RemoteAction::Lattice {
                            namespace: ns.clone(),
                            delta: delta.clone(),
                        });
                        self.wdata.processor.send(Action::Lattice {
                            namespace: ns.clone(),
                            delta: delta,
                        });
                        State::Done
                    }
                    Err(_) => {
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Done => unreachable!(),
            State::Error(e) => State::Error(e),
        };
        Ok(Async::Ready(data.len()))
    }
    fn start_response(&mut self, mut e: http::Encoder<S>)
        -> Self::ResponseFuture
    {
        if let State::Error(status) = self.state {
            e.status(status);
            // TODO(tailhook) add some body describing the error
            e.add_length(0).unwrap();
            e.done_headers().unwrap();
            ok(e.done())
        } else {
            e.status(Status::NoContent);
            e.done_headers().unwrap();
            ok(e.done())
        }
    }
}
<commit_msg>chat replication: fix typo causing not working unsubscribe<commit_after>use std::fmt;
use std::mem;
use std::sync::Arc;
use std::net::SocketAddr;

use futures::Async;
use futures::future::{FutureResult, ok};
use tk_http::Status;
use tk_http::server::{Dispatcher, Error, Head};
use tk_http::server as http;
use tk_http::server::{EncoderDone, RecvMode};
use serde_json::{self, Value as Json};

use intern::{Topic, Lattice as Namespace};
use chat::cid::PubCid;
use chat::processor::Action;
use chat::processor::Delta;
use chat::listener::spawn::WorkerData;
use chat::replication::RemoteAction;

pub struct Handler {
    addr: SocketAddr,
    wdata: Arc<WorkerData>,
}

pub enum State {
    Query(Route),
    Done,
    Error(Status),
}

pub struct Request {
    wdata: Arc<WorkerData>,
    state: State,
}

pub enum Route {
    /// `PUT /v1/connection/<conn_id>/subscriptions/<path>`
    Subscribe(PubCid, Topic),
    /// `DELETE /v1/connection/<conn_id>/subscriptions/<path>`
    Unsubscribe(PubCid, Topic),
    /// `POST /v1/publish/<path>`
    Publish(Topic),
    /// `PUT /v1/connection/<conn_id>/lattices/<namespace>`
    LatticeSubscribe(PubCid, Namespace),
    /// `DELETE /v1/connection/<conn_id>/lattices/<namespace>`
    Detach(PubCid, Namespace),
    /// `POST /v1/lattice/<namespace>`
    Lattice(Namespace),
}

impl fmt::Display for Route {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        use self::Route::*;
        match *self {
            Subscribe(ref cid, ref tpc) => {
                write!(f, "Subscribe {:#?} {:?}", cid.0, tpc)
            }
            Unsubscribe(ref cid, ref tpc) => {
                write!(f, "Unsubscribe {:#?} {:?}", cid.0, tpc)
            }
            Publish(ref topic) => write!(f, "Publish {:?}", topic),
            LatticeSubscribe(ref cid, ref ns) => {
                write!(f, "Lattice subscribe {:#?} {:?}", cid.0, ns)
            }
            Detach(ref cid, ref ns) => {
                write!(f, "Lattice detach {:#?} {:?}", cid.0, ns)
            }
            Lattice(ref ns) => write!(f, "Lattice update {:?}", ns),
        }
    }
}

impl Handler {
    pub fn new(addr: SocketAddr, wdata: Arc<WorkerData>)
        -> Handler
    {
        Handler {
            addr: addr,
            wdata: wdata,
        }
    }
}

impl<S> Dispatcher<S> for Handler {
    type Codec = Request;
    fn headers_received(&mut self, headers: &Head)
        -> Result<Self::Codec, Error>
    {
        let query = match headers.path() {
            Some(path) => {
                if !path.starts_with("/v1/") {
                    State::Error(Status::NotFound)
                } else {
                    self.dispatch(&path[4..], headers.method())
                }
            }
            None => {
                State::Error(Status::BadRequest)
            }
        };
        match query {
            State::Query(ref route) => {
                info!("{:?} received {} (ip: {})",
                    self.wdata.name, route, self.addr);
            }
            State::Done => unreachable!(),
            State::Error(status) => {
                info!("{:?} path {:?} gets {:?} (ip: {})",
                    self.wdata.name, headers.path(), status, self.addr);
            }
        }
        Ok(Request {
            wdata: self.wdata.clone(),
            state: query,
        })
    }
}

impl Handler {
    fn dispatch(&mut self, path: &str, method: &str) -> State {
        let mut iter = path.splitn(2, '/');
        let head = iter.next().unwrap();
        let tail = iter.next();
        match (method, head, tail) {
            (_, "connection", Some(tail)) => {
                let mut p = tail.splitn(3, '/');
                let cid = p.next().and_then(|x| x.parse().ok());
                let middle = p.next();
                let tail = p.next();
                match middle {
                    Some("subscriptions") => {
                        let topic = tail.and_then(|x| {
                            if !x.contains('.') {
                                x.replace("/", ".").parse().ok()
                            } else {
                                None
                            }
                        });
                        match (method, cid, topic) {
                            ("PUT", Some(cid), Some(t)) => {
                                State::Query(Route::Subscribe(cid, t))
                            }
                            ("DELETE", Some(cid), Some(t)) => {
                                State::Query(Route::Unsubscribe(cid, t))
                            }
                            _ => State::Error(Status::NotFound),
                        }
                    }
                    Some("lattices") => {
                        let ns = tail.and_then(|x| {
                            if !x.contains('.') {
                                x.replace("/", ".").parse().ok()
                            } else {
                                None
                            }
                        });
                        match (method, cid, ns) {
                            ("PUT", Some(cid), Some(ns)) => {
                                State::Query(Route::LatticeSubscribe(cid, ns))
                            }
                            ("DELETE", Some(cid), Some(ns)) => {
                                State::Query(Route::Detach(cid, ns))
                            }
                            _ => State::Error(Status::NotFound),
                        }
                    }
                    _ => State::Error(Status::NotFound),
                }
            }
            ("POST", "publish", Some(tail)) => {
                let topic = if !tail.contains('.') {
                    tail.replace("/", ".").parse().ok()
                } else {
                    None
                };
                if let Some(topic) = topic {
                    State::Query(Route::Publish(topic))
                } else {
                    State::Error(Status::NotFound)
                }
            }
            ("POST", "lattice", Some(tail)) => {
                let ns = if !tail.contains('.') {
                    tail.replace("/", ".").parse().ok()
                } else {
                    None
                };
                if let Some(ns) = ns {
                    State::Query(Route::Lattice(ns))
                } else {
                    State::Error(Status::NotFound)
                }
            }
            _ => {
                State::Error(Status::NotFound)
            }
        }
    }
}

impl<S> http::Codec<S> for Request {
    type ResponseFuture = FutureResult<EncoderDone<S>, Error>;
    fn recv_mode(&mut self) -> RecvMode {
        RecvMode::buffered_upfront(self.wdata.settings.max_payload_size)
    }
    fn data_received(&mut self, data: &[u8], end: bool)
        -> Result<Async<usize>, Error>
    {
        use self::Route::*;
        assert!(end);
        let my_srv_id = self.wdata.runtime.server_id;
        let query = mem::replace(&mut self.state,
                                 State::Error(Status::InternalServerError));
        self.state = match query {
            State::Query(Subscribe(PubCid(cid, srv_id), topic)) => {
                if data.len() == 0 {
                    if srv_id == my_srv_id {
                        self.wdata.processor.send(Action::Subscribe {
                            conn_id: cid,
                            topic: topic.clone(),
                        });
                    } else {
                        debug!("Skipping action with non-local cid");
                    }
                    self.wdata.remote.send(RemoteAction::Subscribe {
                        conn_id: cid,
                        server_id: srv_id,
                        topic: topic,
                    });
                    State::Done
                } else {
                    State::Error(Status::BadRequest)
                }
            }
            State::Query(Unsubscribe(PubCid(cid, srv_id), topic)) => {
                if data.len() == 0 {
                    if srv_id == my_srv_id {
                        self.wdata.processor.send(Action::Unsubscribe {
                            conn_id: cid,
                            topic: topic.clone(),
                        });
                    } else {
                        debug!("Skipping action with non-local cid");
                    }
                    self.wdata.remote.send(RemoteAction::Unsubscribe {
                        conn_id: cid,
                        server_id: srv_id,
                        topic: topic,
                    });
                    State::Done
                } else {
                    State::Error(Status::BadRequest)
                }
            }
            State::Query(Publish(topic)) => {
                // TODO(tailhook) check content-type
                match serde_json::from_slice(data) {
                    Ok(json) => {
                        // Send this Action to Replication Queue
                        let data: Arc<Json> = Arc::new(json);
                        self.wdata.remote.send(RemoteAction::Publish {
                            topic: topic.clone(),
                            data: data.clone(),
                        });
                        self.wdata.processor.send(Action::Publish {
                            topic: topic,
                            data: data,
                        });
                        State::Done
                    }
                    Err(e) => {
                        info!("Error decoding json for '/v1/publish': \
                            {:?}", e);
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Query(LatticeSubscribe(PubCid(cid, srv_id), ns)) => {
                // TODO(tailhook) check content-type
                let data: Result<Delta,_> = serde_json::from_slice(data)
                    .map_err(|e| {
                        info!("Error decoding json for \
                            '/v1/lattice/_/subscribe': \
                            {:?}", e);
                    });
                match data {
                    Ok(delta) => {
                        self.wdata.remote.send(RemoteAction::Lattice {
                            namespace: ns.clone(),
                            delta: delta.clone(),
                        });
                        self.wdata.remote.send(RemoteAction::Attach {
                            namespace: ns.clone(),
                            conn_id: cid,
                            server_id: srv_id,
                        });
                        self.wdata.processor.send(Action::Lattice {
                            namespace: ns.clone(),
                            delta: delta,
                        });
                        if srv_id == my_srv_id {
                            self.wdata.processor.send(Action::Attach {
                                namespace: ns.clone(),
                                conn_id: cid,
                            });
                        } else {
                            debug!("Skipping action with non-local cid");
                        }
                        State::Done
                    }
                    Err(_) => {
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Query(Detach(PubCid(cid, srv_id), ns)) => {
                self.wdata.remote.send(RemoteAction::Detach {
                    namespace: ns.clone(),
                    conn_id: cid.clone(),
                    server_id: srv_id,
                });
                if srv_id == my_srv_id {
                    self.wdata.processor.send(Action::Detach {
                        namespace: ns.clone(),
                        conn_id: cid,
                    });
                } else {
                    debug!("Skipping action with non-local cid");
                }
                State::Done
            }
            State::Query(Lattice(ns)) => {
                // TODO(tailhook) check content-type
                let data: Result<Delta,_> = serde_json::from_slice(data)
                    .map_err(|e| {
                        info!("Error decoding json for \
                            '/v1/lattice': \
                            {:?}", e);
                    });
                match data {
                    Ok(delta) => {
                        // Send this Action to Replication Queue
                        self.wdata.remote.send(RemoteAction::Lattice {
                            namespace: ns.clone(),
                            delta: delta.clone(),
                        });
                        self.wdata.processor.send(Action::Lattice {
                            namespace: ns.clone(),
                            delta: delta,
                        });
                        State::Done
                    }
                    Err(_) => {
                        State::Error(Status::BadRequest)
                    }
                }
            }
            State::Done => unreachable!(),
            State::Error(e) => State::Error(e),
        };
        Ok(Async::Ready(data.len()))
    }
    fn start_response(&mut self, mut e: http::Encoder<S>)
        -> Self::ResponseFuture
    {
        if let State::Error(status) = self.state {
            e.status(status);
            // TODO(tailhook) add some body describing the error
            e.add_length(0).unwrap();
            e.done_headers().unwrap();
            ok(e.done())
        } else {
            e.status(Status::NoContent);
            e.done_headers().unwrap();
            ok(e.done())
        }
    }
}
<|endoftext|>


<commit_before>// Compare bounded and unbounded protocol performance.

// xfail-pretty

use std;

import pipes::{spawn_service, recv};
import std::time::precise_time_s;

proto! pingpong {
    ping: send {
        ping -> pong
    }

    pong: recv {
        pong -> ping
    }
}

proto! pingpong_unbounded {
    ping: send {
        ping -> pong
    }

    pong: recv {
        pong -> ping
    }

    you_will_never_catch_me: send {
        never_ever_ever -> you_will_never_catch_me
    }
}

// This stuff should go in libcore::pipes
macro_rules! move {
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
}

macro_rules! follow {
    {
        $($message:path($($x: ident),+) -> $next:ident $e:expr)+
    } => (
        |m| alt move(m) {
          $(some($message($($x,)* next)) {
            let $next = move!{next};
            $e })+
          _ { fail }
        }
    );

    {
        $($message:path -> $next:ident $e:expr)+
    } => (
        |m| alt move(m) {
            $(some($message(next)) {
                let $next = move!{next};
                $e })+
                _ { fail }
        }
    )
}

fn switch<T: send, Tb: send, U>(+endp: pipes::recv_packet_buffered<T, Tb>,
                      f: fn(+option<T>) -> U) -> U {
    f(pipes::try_recv(endp))
}

fn move<T>(-x: T) -> T { x }

// Here's the benchmark

fn bounded(count: uint) {
    import pingpong::*;

    let mut ch = do spawn_service(init) |ch| {
        let mut count = count;
        let mut ch = ch;
        while count > 0 {
            ch = switch(ch, follow! {
                ping -> next { server::pong(next) }
            });

            count -= 1;
        }
    };

    let mut count = count;
    while count > 0 {
        let ch_ = client::ping(ch);

        ch = switch(ch_, follow! {
            pong -> next { next }
        });

        count -= 1;
    }
}

fn unbounded(count: uint) {
    import pingpong_unbounded::*;

    let mut ch = do spawn_service(init) |ch| {
        let mut count = count;
        let mut ch = ch;
        while count > 0 {
            ch = switch(ch, follow! {
                ping -> next { server::pong(next) }
            });

            count -= 1;
        }
    };

    let mut count = count;
    while count > 0 {
        let ch_ = client::ping(ch);

        ch = switch(ch_, follow! {
            pong -> next { next }
        });

        count -= 1;
    }
}

fn timeit(f: fn()) -> float {
    let start = precise_time_s();
    f();
    let stop = precise_time_s();
    stop - start
}

fn main() {
    let count = 1000000;
    let bounded = do timeit { bounded(count) };
    let unbounded = do timeit { unbounded(count) };

    io::println(#fmt("count: %?\n", count));
    io::println(#fmt("bounded:   %? s\t(%? μs/message)",
                     bounded, bounded * 1000000. / (count as float)));
    io::println(#fmt("unbounded: %? s\t(%? μs/message)",
                     unbounded, unbounded * 1000000. / (count as float)));

    io::println(#fmt("\n\
                      bounded is %?%% faster",
                     (unbounded - bounded) / bounded * 100.));
}
<commit_msg>re-xfailing pingpong<commit_after>// Compare bounded and unbounded protocol performance.

// xfail-test
// xfail-pretty

use std;

import pipes::{spawn_service, recv};
import std::time::precise_time_s;

proto! pingpong {
    ping: send {
        ping -> pong
    }

    pong: recv {
        pong -> ping
    }
}

proto! pingpong_unbounded {
    ping: send {
        ping -> pong
    }

    pong: recv {
        pong -> ping
    }

    you_will_never_catch_me: send {
        never_ever_ever -> you_will_never_catch_me
    }
}

// This stuff should go in libcore::pipes
macro_rules! move {
    { $x:expr } => { unsafe { let y <- *ptr::addr_of($x); y } }
}

macro_rules! follow {
    {
        $($message:path($($x: ident),+) -> $next:ident $e:expr)+
    } => (
        |m| alt move(m) {
          $(some($message($($x,)* next)) {
            let $next = move!{next};
            $e })+
          _ { fail }
        }
    );

    {
        $($message:path -> $next:ident $e:expr)+
    } => (
        |m| alt move(m) {
            $(some($message(next)) {
                let $next = move!{next};
                $e })+
                _ { fail }
        }
    )
}

fn switch<T: send, Tb: send, U>(+endp: pipes::recv_packet_buffered<T, Tb>,
                      f: fn(+option<T>) -> U) -> U {
    f(pipes::try_recv(endp))
}

fn move<T>(-x: T) -> T { x }

// Here's the benchmark

fn bounded(count: uint) {
    import pingpong::*;

    let mut ch = do spawn_service(init) |ch| {
        let mut count = count;
        let mut ch = ch;
        while count > 0 {
            ch = switch(ch, follow! {
                ping -> next { server::pong(next) }
            });

            count -= 1;
        }
    };

    let mut count = count;
    while count > 0 {
        let ch_ = client::ping(ch);

        ch = switch(ch_, follow! {
            pong -> next { next }
        });

        count -= 1;
    }
}

fn unbounded(count: uint) {
    import pingpong_unbounded::*;

    let mut ch = do spawn_service(init) |ch| {
        let mut count = count;
        let mut ch = ch;
        while count > 0 {
            ch = switch(ch, follow! {
                ping -> next { server::pong(next) }
            });

            count -= 1;
        }
    };

    let mut count = count;
    while count > 0 {
        let ch_ = client::ping(ch);

        ch = switch(ch_, follow! {
            pong -> next { next }
        });

        count -= 1;
    }
}

fn timeit(f: fn()) -> float {
    let start = precise_time_s();
    f();
    let stop = precise_time_s();
    stop - start
}

fn main() {
    let count = 1000000;
    let bounded = do timeit { bounded(count) };
    let unbounded = do timeit { unbounded(count) };

    io::println(#fmt("count: %?\n", count));
    io::println(#fmt("bounded:   %? s\t(%? μs/message)",
                     bounded, bounded * 1000000. / (count as float)));
    io::println(#fmt("unbounded: %? s\t(%? μs/message)",
                     unbounded, unbounded * 1000000. / (count as float)));

    io::println(#fmt("\n\
                      bounded is %?%% faster",
                     (unbounded - bounded) / bounded * 100.));
}
<|endoftext|>


<commit_before>use bot::LalafellBot;
use database::models::{Message as DbMessage, Edit};

use lalafell::bot::Bot;
use lalafell::commands::prelude::*;
use lalafell::error::*;

use discord::model::{Message, LiveServer, PublicChannel, permissions};

use diesel::prelude::*;

use std::sync::Arc;

const USAGE: &'static str = "!viewedits <message ID>";

pub struct ViewEditsCommand {
  bot: Arc<LalafellBot>
}

impl ViewEditsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> ViewEditsCommand {
    ViewEditsCommand {
      bot: bot
    }
  }
}

impl HasBot for ViewEditsCommand {
  fn bot(&self) -> &Bot {
    self.bot.as_ref()
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  message_id: u64
}

impl HasParams for ViewEditsCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for ViewEditsCommand {
  fn run(&self, message: &Message, server: &LiveServer, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let has_perms = server.permissions_for(channel.id, message.author.id).contains(permissions::MANAGE_MESSAGES);
    if !has_perms {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let message: Option<DbMessage> = ::bot::CONNECTION.with(|c| {
      use database::schema::messages::dsl;
      dsl::messages
        .filter(dsl::message_id.eq(params.message_id.to_string()))
        .first::<DbMessage>(c)
        .optional()
        .chain_err(|| "could not load messages")
    })?;
    let message = match message {
      Some(m) => m,
      None => return Err("No message with that ID recorded.".into())
    };

    let edits: Vec<Edit> = ::bot::CONNECTION.with(|c| Edit::belonging_to(&message).load(c).chain_err(|| "could not load edits"))?;
    if edits.is_empty() {
      return Err("That message has not been edited.".into());
    }

    let mut result = String::new();
    let mut messages: Vec<String> = edits.into_iter().map(|x| x.content).collect();
    messages.insert(0, message.content);

    for edits in messages.windows(2) {
      result.push_str("- ");
      result.push_str(&edits[0]);
      result.push('\n');
      result.push_str("+ ");
      result.push_str(&edits[1]);
      result.push_str("\n\n");
    }

    Ok(format!("```diff\n{}```", result).into())
  }
}
<commit_msg>fix: don't allow viewing edits of other servers<commit_after>use bot::LalafellBot;
use database::models::{Message as DbMessage, Edit};

use lalafell::bot::Bot;
use lalafell::commands::prelude::*;
use lalafell::error::*;

use discord::model::{Message, LiveServer, PublicChannel, permissions};

use diesel::prelude::*;

use std::sync::Arc;

const USAGE: &'static str = "!viewedits <message ID>";

pub struct ViewEditsCommand {
  bot: Arc<LalafellBot>
}

impl ViewEditsCommand {
  pub fn new(bot: Arc<LalafellBot>) -> ViewEditsCommand {
    ViewEditsCommand {
      bot: bot
    }
  }
}

impl HasBot for ViewEditsCommand {
  fn bot(&self) -> &Bot {
    self.bot.as_ref()
  }
}

#[derive(Debug, Deserialize)]
pub struct Params {
  message_id: u64
}

impl HasParams for ViewEditsCommand {
  type Params = Params;
}

impl<'a> PublicChannelCommand<'a> for ViewEditsCommand {
  fn run(&self, message: &Message, server: &LiveServer, channel: &PublicChannel, params: &[&str]) -> CommandResult<'a> {
    let params = self.params(USAGE, params)?;

    let has_perms = server.permissions_for(channel.id, message.author.id).contains(permissions::MANAGE_MESSAGES);
    if !has_perms {
      return Err(ExternalCommandFailure::default()
        .message(|e: EmbedBuilder| e
          .title("Not enough permissions.")
          .description("You don't have enough permissions to use this command."))
        .wrap());
    }

    let message: Option<DbMessage> = ::bot::CONNECTION.with(|c| {
      use database::schema::messages::dsl;
      dsl::messages
        .filter(dsl::message_id.eq(params.message_id.to_string()))
        .first::<DbMessage>(c)
        .optional()
        .chain_err(|| "could not load messages")
    })?;
    let message = match message {
      Some(m) => m,
      None => return Err("No message with that ID recorded.".into())
    };

    if !server.channels.iter().any(|c| c.id.0 == *message.channel_id) {
      return Err("You cannot view messages not on the current server.".into());
    }

    let edits: Vec<Edit> = ::bot::CONNECTION.with(|c| Edit::belonging_to(&message).load(c).chain_err(|| "could not load edits"))?;
    if edits.is_empty() {
      return Err("That message has not been edited.".into());
    }

    let mut result = String::new();
    let mut messages: Vec<String> = edits.into_iter().map(|x| x.content).collect();
    messages.insert(0, message.content);

    for edits in messages.windows(2) {
      result.push_str("- ");
      result.push_str(&edits[0]);
      result.push('\n');
      result.push_str("+ ");
      result.push_str(&edits[1]);
      result.push_str("\n\n");
    }

    Ok(format!("```diff\n{}```", result).into())
  }
}
<|endoftext|>


<commit_before>extern crate dft;
#[macro_use(tensor)]
extern crate numeric;
use numeric::{Tensor, AxisIndex};
use dft::{Operation, Plan, Transform, c64};
use std::iter::FromIterator;
use std::f64::consts::PI;

fn main()
{
    let size: usize = 32;
    let planf        = Plan::new(dft::Operation::Forward, size);
    let plani        = Plan::new(dft::Operation::Inverse, size);
    let mut a        = Tensor::new( Vec::from_iter ((0..size) .map(|idx| c64::new((idx+1) as f64, 0.0))));
    let mut b        = tensor![c64::new(0.0, 0.0); size];
    let mut kernel   = Tensor::new( Vec::from_iter ((0..size) .map(|idx|
                                                        c64::new( (2.0*PI * 3.0*(idx as f64) / (size as f64)).cos(),
                                                                  (2.0*PI * 3.0*(idx as f64) / (size as f64)).sin() ))));

    println!("a: {:?}, kernel: {:?}", a.data(), kernel.data());

    //(*a.data()).transform(&planf);
    //let mut data = vec![c64::new(42.0, 69.0); size];
    //data.transform(&planf);
}
<commit_msg>finished `fourier_shift_convolution` sample.<commit_after>extern crate dft;
use dft::{Operation, Plan, Transform, c64};
use std::iter::FromIterator;
use std::f64::consts::PI;

fn main()
{
    let size: usize = 32;
    let planf        = Plan::new(dft::Operation::Forward, size);
    let plani        = Plan::new(dft::Operation::Inverse, size);
    let mut a        = Vec::from_iter ((0..size) .map(|idx| c64::new((idx+1) as f64, 0.0)));
    let mut kernel   = Vec::from_iter ((0..size) .map(|idx| c64::new( (2.0*PI * 3.0*(idx as f64) / (size as f64)).cos(),
                                                                      (2.0*PI * 3.0*(idx as f64) / (size as f64)).sin() )));
    println!("a: {:?}, kernel: {:?}", a, kernel);

    // forward Fourier transform
    a.transform(&planf);

    // convolution with the kernel
    let mut b        = Vec::from_iter ((0..size) .map(|i| a[i] * kernel[i]));

    b.transform(&plani);
    println!("b: {:?}", b);
}
<|endoftext|>


<commit_before>use std::str::FromStr;
use std::slice;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// Like floor, but map generation treats it differently.
    Corridor,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_irregular: bool,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_irregular: false },
    Gate:        TerrainData { name: "gate",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_irregular: false },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_irregular: false },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_irregular: false },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_irregular: false },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_irregular: false },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_irregular: false },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "",    is_irregular: false },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "",    is_irregular: false },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_irregular: false },
    // TODO: Get rid of corridor, it only makes sense for mapgen bookkeeping and that doesn't
    // belong in persistent map.
    Corridor:    TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: "_.,", is_irregular: true },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_irregular: true },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_irregular: true },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> {
        TERRAIN_ENUM.iter()
    }

    #[inline(always)]
    pub fn kind(self) -> Kind {
        TERRAIN_DATA[self as usize].kind
    }

    #[inline(always)]
    pub fn form(self) -> Form {
        TERRAIN_DATA[self as usize].form
    }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Corridor | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground || self.kind() == Kind::Corridor }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_irregular(self) -> bool { TERRAIN_DATA[self as usize].is_irregular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str {
        &TERRAIN_DATA[self as usize].map_chars
    }
}

impl FromStr for Terrain {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        for t in Terrain::iter() {
            if &format!("{:?}", t) == s {
                return Ok(*t);
            }
        }
        Err(format!("Unknown terrain '{}'", s))
    }
}
<commit_msg>Fix preferred map chars<commit_after>use std::str::FromStr;
use std::slice;

/// Movement effect of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Kind {
    /// Regular flat solid ground, can walk across easily.
    Ground,
    /// Like floor, but map generation treats it differently.
    Corridor,
    /// An obstacle that fills the entire cell, blocks field of view.
    Block,
    /// An obstacle that can be seen through.
    ///
    /// Not necessarily a literal window, thinner blocks like pillars and statues might also be
    /// see-through.
    Window,
    /// A tile that blocks sight but can be walked through.
    Door,
    /// Bodies of water, regular units can't walk into them.
    ///
    /// Flying units (if we have any) can cross. Falling into water is going to involve tricky
    /// logic since our maps aren't 3D.
    Water,
    /// Like water, but much more fun.
    Magma,
}

/// Visual form of a terrain tile.
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
pub enum Form {
    /// Nothingness, lets sight pass through portals
    Void,
    /// Marker pointing at adjacent nothingness
    Gate,
    /// Single frame on floor layer
    Floor,
    /// Single frame on object layer
    Prop,
    /// Blobbing form on object layer
    Blob,
    /// Wall-form on object layer
    Wall,
}

struct TerrainData {
    name: &'static str,
    kind: Kind,
    form: Form,
    map_chars: &'static str,
    /// For variants that should not show up in main terrain sets.
    is_irregular: bool,
}

macro_rules! count_tts {
    () => {0usize};
    ($_head:tt $($tail:tt)*) => {1usize + count_tts!($($tail)*)};
}

macro_rules! terrain_enum {
    {
        $($sym:ident: $data:expr,)+
    } => {
        #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Serialize, Deserialize)]
        pub enum Terrain {
            $($sym,)+
        }

        const N_ENUM: usize = count_tts!($($sym)+);

        static TERRAIN_DATA: [TerrainData; N_ENUM] = [
            $($data,)+
        ];

        static TERRAIN_ENUM: [Terrain; N_ENUM] = [
            $(Terrain::$sym,)+
        ];
    }
}

terrain_enum! {
    Empty:       TerrainData { name: "void",      kind: Kind::Block,  form: Form::Void,  map_chars: "",    is_irregular: false },
    Gate:        TerrainData { name: "gate",      kind: Kind::Ground, form: Form::Gate,  map_chars: ">",   is_irregular: false },
    Ground:      TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: ".,_", is_irregular: false },
    Grass:       TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: ",._", is_irregular: false },
    Water:       TerrainData { name: "water",     kind: Kind::Water,  form: Form::Floor, map_chars: "~=",  is_irregular: false },
    Magma:       TerrainData { name: "magma",     kind: Kind::Magma,  form: Form::Floor, map_chars: "=~",  is_irregular: false },
    Tree:        TerrainData { name: "tree",      kind: Kind::Block,  form: Form::Prop,  map_chars: "",    is_irregular: false },
    Wall:        TerrainData { name: "wall",      kind: Kind::Block,  form: Form::Wall,  map_chars: "#*",  is_irregular: false },
    Rock:        TerrainData { name: "rock",      kind: Kind::Block,  form: Form::Blob,  map_chars: "*#",  is_irregular: false },
    Door:        TerrainData { name: "door",      kind: Kind::Door,   form: Form::Wall,  map_chars: "|",   is_irregular: false },
    // TODO: Get rid of corridor, it only makes sense for mapgen bookkeeping and that doesn't
    // belong in persistent map.
    Corridor:    TerrainData { name: "ground",    kind: Kind::Ground, form: Form::Floor, map_chars: "_.,", is_irregular: true },
    OpenDoor:    TerrainData { name: "open door", kind: Kind::Ground, form: Form::Wall,  map_chars: "",    is_irregular: true },
    // TODO: Get rid of grass2, give render a coherent noise source for tiles and make it do the
    // variation locally.
    Grass2:      TerrainData { name: "grass",     kind: Kind::Ground, form: Form::Floor, map_chars: "",    is_irregular: true },
}

impl Terrain {
    pub fn iter() -> slice::Iter<'static, Terrain> {
        TERRAIN_ENUM.iter()
    }

    #[inline(always)]
    pub fn kind(self) -> Kind {
        TERRAIN_DATA[self as usize].kind
    }

    #[inline(always)]
    pub fn form(self) -> Form {
        TERRAIN_DATA[self as usize].form
    }

    pub fn blocks_sight(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_shot(self) -> bool {
        match self.kind() {
            Kind::Block | Kind::Window | Kind::Door => true,
            _ => false,
        }
    }

    pub fn blocks_walk(self) -> bool {
        match self.kind() {
            Kind::Ground | Kind::Corridor | Kind::Door => false,
            _ => true,
        }
    }

    pub fn name(self) -> &'static str { TERRAIN_DATA[self as usize].name }

    pub fn is_open(self) -> bool { self.kind() == Kind::Ground || self.kind() == Kind::Corridor }

    pub fn is_door(self) -> bool { self.kind() == Kind::Door }

    pub fn is_luminous(self) -> bool { self.kind() == Kind::Magma }

    pub fn is_wall(self) -> bool { self.form() == Form::Wall }

    pub fn is_hull(self) -> bool { self.form() == Form::Wall || self.form() == Form::Blob }

    pub fn is_blob(self) -> bool { self.form() == Form::Blob }

    pub fn is_block(self) -> bool { self.is_hull() || self.form() == Form::Prop }

    pub fn is_irregular(self) -> bool { TERRAIN_DATA[self as usize].is_irregular }

    /// For constructing text maps.
    pub fn preferred_map_chars(self) -> &'static str {
        &TERRAIN_DATA[self as usize].map_chars
    }
}

impl FromStr for Terrain {
    type Err = String;
    fn from_str(s: &str) -> Result<Self, Self::Err> {
        for t in Terrain::iter() {
            if &format!("{:?}", t) == s {
                return Ok(*t);
            }
        }
        Err(format!("Unknown terrain '{}'", s))
    }
}
<|endoftext|>


<commit_before>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containing matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();

    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    info!("{} files, {} workers (I'm #{}), chunks of {}", mats.len(), size, rank, chunksize);

    let mut accum = None;
    for matname in mats.into_iter().skip(rank*chunksize).take(chunksize) {
        let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)?;
        let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)?;

        info!("Reading {} ({} GB) ..", matname, matname.len() >> 27);
        accum = Some(match accum {
            Some(mut acc) => {acc += mat; acc}
            None => mat.to_owned()
        });
    }
    if let Some(ref acc) = accum {
        cabarrus::numpy::write_matrix(args.value_of("output").unwrap(), acc)?;
    } else {
        info!("No matrices processed so nothing saved.");
    }
    Ok(())
}
<commit_msg>mat size is wrong<commit_after>/// MPI-based method for summing many arrays

// Argument parsing
// logging
#[macro_use] extern crate log;
#[macro_use] extern crate clap;
extern crate ndarray;
extern crate env_logger;
// lastly, this library
extern crate cabarrus;
use cabarrus::errors::*;

pub fn main() {
    // Main can't return a Result, and the ? operator needs the enclosing function to return Result
    inner_main().expect("Could not recover. Exiting.");
}
pub fn inner_main() -> Result<()> {
    env_logger::init().unwrap();
    let args = app_from_crate!()
        .arg_from_usage("<size> 'how many workers there are'")
        .arg_from_usage("<rank> 'which worker am I, starting from 0'")
        .arg_from_usage("<addends>.. 'files containing matrices to add'")
        .arg_from_usage("<output> 'file in which to store the resulting matrix'")
        .get_matches();

    let mut mats : Vec<&str> = args.values_of("addends").unwrap().collect();
    mats.sort();

    let size = value_t!(args, "size", usize).unwrap_or_else(|e| e.exit());
    let rank = value_t!(args, "rank", usize).unwrap_or_else(|e| e.exit());
    let chunksize = (mats.len() + size - 1) / size;
    info!("{} files, {} workers (I'm #{}), chunks of {}", mats.len(), size, rank, chunksize);

    let mut accum = None;
    for matname in mats.into_iter().skip(rank*chunksize).take(chunksize) {
        let ref matfile = cabarrus::numpy::open_matrix_mmap(matname)?;
        let ref mat = cabarrus::numpy::read_matrix_mmap(matfile)?;

        info!("Reading {} ({} GB) ..", matname, mat.len() >> 27);
        accum = Some(match accum {
            Some(mut acc) => {acc += mat; acc}
            None => mat.to_owned()
        });
    }
    if let Some(ref acc) = accum {
        cabarrus::numpy::write_matrix(args.value_of("output").unwrap(), acc)?;
    } else {
        info!("No matrices processed so nothing saved.");
    }
    Ok(())
}
<|endoftext|>


<commit_before>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let param = h.param(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"each\""));
        }

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param.unwrap());

                rc.promote_local_vars();

                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (len > 1 && i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            let new_path = format!("{}/{}[{}]", path, param.unwrap(), i);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = format!("{}/{}/{}", path, param.unwrap(), k);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(), "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m :BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

}
<commit_msg>Fix @last on a single-element array #each.<commit_after>use serialize::json::{Json, ToJson};

use helpers::{HelperDef};
use registry::{Registry};
use context::{Context};
use render::{Renderable, RenderContext, RenderError, render_error, Helper};

#[derive(Clone, Copy)]
pub struct EachHelper;

impl HelperDef for EachHelper{
    fn call(&self, c: &Context, h: &Helper, r: &Registry, rc: &mut RenderContext) -> Result<(), RenderError> {
        let param = h.param(0);

        if param.is_none() {
            return Err(render_error("Param not found for helper \"each\""));
        }

        let template = h.template();

        match template {
            Some(t) => {
                let path = rc.get_path().clone();
                let value = c.navigate(&path, param.unwrap());

                rc.promote_local_vars();

                let rendered = match *value {
                    Json::Array (ref list) => {
                        let len = list.len();
                        for i in 0..len {
                            rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
                            rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
                            rc.set_local_var("@index".to_string(), i.to_json());

                            let new_path = format!("{}/{}[{}]", path, param.unwrap(), i);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }
                        Ok(())
                    },
                    Json::Object(ref obj) => {
                        let mut first:bool = true;
                        for k in obj.keys() {
                            rc.set_local_var("@first".to_string(), first.to_json());
                            if first {
                                first = false;
                            }

                            rc.set_local_var("@key".to_string(), k.to_json());
                            let new_path = format!("{}/{}/{}", path, param.unwrap(), k);
                            rc.set_path(new_path);
                            try!(t.render(c, r, rc));
                        }

                        Ok(())
                    },
                    _ => {
                        Err(render_error("Param is not an iteratable."))
                    }
                };
                rc.set_path(path);
                rc.demote_local_vars();
                rendered
            },
            None => Ok(())
        }
    }
}

pub static EACH_HELPER: EachHelper = EachHelper;

#[cfg(test)]
mod test {
    use template::{Template};
    use registry::{Registry};

    use std::collections::BTreeMap;

    #[test]
    fn test_each() {
        let t0 = Template::compile("{{#each this}}{{@first}}|{{@last}}|{{@index}}:{{this}}|{{/each}}".to_string()).ok().unwrap();
        let t1 = Template::compile("{{#each this}}{{@first}}|{{@key}}:{{this}}|{{/each}}".to_string()).ok().unwrap();

        let mut handlebars = Registry::new();
        handlebars.register_template("t0", t0);
        handlebars.register_template("t1", t1);

        let r0 = handlebars.render("t0", &vec![1u16, 2u16, 3u16]);
        assert_eq!(r0.ok().unwrap(), "true|false|0:1|false|false|1:2|false|true|2:3|".to_string());

        let mut m :BTreeMap<String, u16> = BTreeMap::new();
        m.insert("ftp".to_string(), 21);
        m.insert("http".to_string(), 80);
        let r1 = handlebars.render("t1", &m);
        assert_eq!(r1.ok().unwrap(), "true|ftp:21|false|http:80|".to_string());
    }

}
<|endoftext|>