<commit_before>extern crate libc;

use std::io;
use std::thread;
use std::time::Duration;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr::{ self, read_volatile, write_volatile };

const GPIO_ADDR : libc::off_t      = 0x3F200000; // BCM2836 and BCM2837 GPIO address
const MEM_BLK_SIZE : libc::size_t  = 4096;       // page size(4KB)

const GPFSEL2_OFFSET_ADDR : isize  = 0x02;       // 0x08 / 4
const GPSET0_OFFSET_ADDR : isize   = 0x07;       // 0x1C / 4
const GPCLR0_OFFSET_ADDR : isize   = 0x0A;       // 0x28 / 4
const GPLEV0_OFFSET_ADDR : isize   = 0x0D;       // 0x34 / 4

const FSEL27_BIT : isize    = 21;
const SET27_BIT : isize     = 27;
const CLR27_BIT : isize     = 27;
const LEV27_BIT : isize     = 27;

const GPFSEL_INPUT : u32    = 0;
const GPFSEL_OUTPUT : u32   = 1;
const FSEL27_MASK : u32     = 0xFF1FFFFF;

const GPLEV_HIGH : u32      = 1;
const ON : u32              = 1;

const SLEEP_DELAY : u64     = 1;

fn main() {
    let mut blink_cnt : i32 = 0;
    let gpio_ptr : *mut u32 = map_gpio().expect( "failed to gpio mapping" );
    let fsel2_reg : *mut u32 = unsafe { gpio_ptr.offset( GPFSEL2_OFFSET_ADDR ) };
    let clr0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPCLR0_OFFSET_ADDR ) };

    unsafe {
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_OUTPUT << FSEL27_BIT ) );
    }

    while blink_cnt < 10 {
        blink_led( gpio_ptr );
        thread::sleep( Duration::from_secs( SLEEP_DELAY ) );
        blink_cnt = blink_cnt + 1;
    }

    unsafe {
        write_volatile( clr0_reg, *clr0_reg | ( ( ON << CLR27_BIT ) ) );
        write_volatile( fsel2_reg, ( *fsel2_reg & FSEL27_MASK ) | ( GPFSEL_INPUT << FSEL27_BIT ) );
    }
}

fn map_gpio() -> io::Result<*mut u32>  {
    let mem_file = OpenOptions::new()
                .read( true )
                .write( true )
                .custom_flags( libc::O_SYNC )
                .open( "/dev/gpiomem" )
                .expect( "can't open /dev/gpiomem" );

    unsafe {
        let gpio_ptr = libc::mmap( ptr::null_mut(),
                                   MEM_BLK_SIZE,
                                   libc::PROT_READ | libc::PROT_WRITE,
                                   libc::MAP_SHARED,
                                   mem_file.as_raw_fd(),
                                   GPIO_ADDR );

        if gpio_ptr == libc::MAP_FAILED {
            Err( io::Error::last_os_error() )
        }
        else
        {
            Ok( gpio_ptr as *mut u32 )
        }
    }
}

fn blink_led( gpio_ptr : *mut u32 ) {
    let set0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPSET0_OFFSET_ADDR ) };
    let clr0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPCLR0_OFFSET_ADDR ) };
    let lev0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPLEV0_OFFSET_ADDR ) };
    let level : u32;

    unsafe {
        level = ( read_volatile( lev0_reg ) >> LEV27_BIT ) & 0x00000001;
    }

    if level == GPLEV_HIGH {
        unsafe {
            write_volatile( clr0_reg, *clr0_reg | ( ON << CLR27_BIT ) );
        }
    }
    else
    {
        unsafe {
            write_volatile( set0_reg, *set0_reg | ( ON << SET27_BIT ) );
        }
    }
}
<commit_msg>Change mask set for GPFSEL<commit_after>extern crate libc;

use std::io;
use std::thread;
use std::time::Duration;
use std::fs::OpenOptions;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::ptr::{ self, read_volatile, write_volatile };

const GPIO_ADDR : libc::off_t      = 0x3F200000; // BCM2836 and BCM2837 GPIO address
const MEM_BLK_SIZE : libc::size_t  = 4096;       // page size(4KB)

const GPFSEL2_OFFSET_ADDR : isize  = 0x02;       // 0x08 / 4
const GPSET0_OFFSET_ADDR : isize   = 0x07;       // 0x1C / 4
const GPCLR0_OFFSET_ADDR : isize   = 0x0A;       // 0x28 / 4
const GPLEV0_OFFSET_ADDR : isize   = 0x0D;       // 0x34 / 4

const FSEL27_BIT : isize    = 21;
const SET27_BIT : isize     = 27;
const CLR27_BIT : isize     = 27;
const LEV27_BIT : isize     = 27;

const GPFSEL_INPUT : u32    = 0;
const GPFSEL_OUTPUT : u32   = 1;
const FSEL_MASK_BASE : u32  = 0x00000007;

const GPLEV_HIGH : u32      = 1;
const ON : u32              = 1;

const SLEEP_DELAY : u64     = 1;

fn main() {
    let mut blink_cnt : i32 = 0;
    let gpio_ptr : *mut u32 = map_gpio().expect( "failed to gpio mapping" );
    let fsel2_reg : *mut u32 = unsafe { gpio_ptr.offset( GPFSEL2_OFFSET_ADDR ) };
    let clr0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPCLR0_OFFSET_ADDR ) };

    unsafe {
        write_volatile( fsel2_reg, ( *fsel2_reg & ( FSEL_MASK_BASE << FSEL27_BIT ) ) |
                                     ( GPFSEL_OUTPUT << FSEL27_BIT ) );
    }

    while blink_cnt < 10 {
        blink_led( gpio_ptr );
        thread::sleep( Duration::from_secs( SLEEP_DELAY ) );
        blink_cnt = blink_cnt + 1;
    }

    unsafe {
        write_volatile( clr0_reg, *clr0_reg | ( ( ON << CLR27_BIT ) ) );
        write_volatile( fsel2_reg, ( *fsel2_reg & ( FSEL_MASK_BASE << FSEL27_BIT ) ) |
                        ( GPFSEL_INPUT << FSEL27_BIT ) );
    }
}

fn map_gpio() -> io::Result<*mut u32>  {
    let mem_file = OpenOptions::new()
                .read( true )
                .write( true )
                .custom_flags( libc::O_SYNC )
                .open( "/dev/gpiomem" )
                .expect( "can't open /dev/gpiomem" );

    unsafe {
        let gpio_ptr = libc::mmap( ptr::null_mut(),
                                   MEM_BLK_SIZE,
                                   libc::PROT_READ | libc::PROT_WRITE,
                                   libc::MAP_SHARED,
                                   mem_file.as_raw_fd(),
                                   GPIO_ADDR );

        if gpio_ptr == libc::MAP_FAILED {
            Err( io::Error::last_os_error() )
        }
        else
        {
            Ok( gpio_ptr as *mut u32 )
        }
    }
}

fn blink_led( gpio_ptr : *mut u32 ) {
    let set0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPSET0_OFFSET_ADDR ) };
    let clr0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPCLR0_OFFSET_ADDR ) };
    let lev0_reg : *mut u32 = unsafe { gpio_ptr.offset( GPLEV0_OFFSET_ADDR ) };
    let level : u32;

    unsafe {
        level = ( read_volatile( lev0_reg ) >> LEV27_BIT ) & 0x00000001;
    }

    if level == GPLEV_HIGH {
        unsafe {
            write_volatile( clr0_reg, *clr0_reg | ( ON << CLR27_BIT ) );
        }
    }
    else
    {
        unsafe {
            write_volatile( set0_reg, *set0_reg | ( ON << SET27_BIT ) );
        }
    }
}
<|endoftext|>


<commit_before>struct AddressSpace {
    data: [u8; 0xFFFF],
}

impl AddressSpace {

    fn new() -> AddressSpace {
        AddressSpace { data: [0; 0xFFFF] }
    }

    fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        self.data.slice(addr as usize, (addr + bytes) as usize)
    }

    fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

}

struct Instr<'a> {
    opcode: u8,
    data: Option<&'a [u8]>,
}

impl<'a> Instr<'a> {

    fn new(opcode: u8, data: Option<&[u8]>) -> Instr {
        Instr { opcode: opcode, data: data }
    }

    fn opcode(&self) -> u8 {
        self.opcode
    }

    fn param(&self, i: usize) -> u8 {
        self.data.expect("Instruction type does not carry parameters")[i]
    }

}

enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

}

static GB_FREQUENCY: u32 = 4194304;

struct Cpu {
    reg: RegData,
    ram: AddressSpace,
    freq: u32,
    clock: u64,
    cycle_block: u32,
}

impl Cpu {

    fn new() -> Cpu {
        Cpu::new_with_freq(GB_FREQUENCY)
    }

    fn new_with_freq(freq: u32) -> Cpu {
        Cpu {
            reg: RegData::new(),
            ram: AddressSpace::new(),
            freq: freq,
            clock: 0,
            cycle_block: 0,
        }
    }

    fn next_instr(&mut self) -> Instr {
        let opcode = self.ram.read(self.reg.advance_pc());
        Instr {
            opcode: opcode,
            data: None,
        }
    }

    fn do_cycle(&mut self) {
        self.clock += 1;
        if self.cycle_block > 0 {
            self.cycle_block -= 1;
        } else {
            let instr = self.next_instr();
            match instr.opcode() {
                _ => panic!("Instruction not implemented!"),
            }
        }
    }

}

fn main() {
    println!("Hello, world!");
}
<commit_msg>Redesign instruction parser<commit_after>struct AddressSpace {
    data: [u8; 0xFFFF],
}

impl AddressSpace {

    fn new() -> AddressSpace {
        AddressSpace { data: [0; 0xFFFF] }
    }

    fn read(&self, addr: u16) -> u8 {
        self.data[addr as usize]
    }

    fn read_slice(&self, addr: u16, bytes: u16) -> &[u8] {
        self.data.slice(addr as usize, (addr + bytes) as usize)
    }

    fn write(&mut self, addr: u16, data: u8) {
        self.data[addr as usize] = data;
    }

}

struct Instr<'a> {
    opcode: u8,
    data: Option<&'a [u8]>,
}

impl<'a> Instr<'a> {

    fn parse(reg: &mut RegData, rom: &'a AddressSpace) -> Instr<'a> {
        let opcode = rom.read(reg.advance_pc());
        Instr {
            opcode: opcode,
            data: None,
        }
    }

    fn opcode(&self) -> u8 {
        self.opcode
    }

    fn param(&self, i: usize) -> u8 {
        self.data.expect("Instruction type does not carry parameters")[i]
    }

}

enum RegFlag {
    Zero,
    Subtract,
    HalfCarry,
    Carry,
}

enum Register {
    A,
    B,
    C,
    D,
    E,
    F,
    H,
    L,
    AF,
    BC,
    DE,
    HL,
    SP,
    PC,
    Flag,
}

struct RegData {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
    e: u8,
    f: u8,
    h: u8,
    l: u8,
    sp: u16,
    pc: u16,
    flag: u8,
}

impl RegData {

    fn new() -> RegData {
        RegData {
            a: 0,
            b: 0,
            c: 0,
            d: 0,
            e: 0,
            f: 0,
            h: 0,
            l: 0,
            sp: 0xFFFE,
            pc: 0x100,
            flag: 0,
        }
    }

    fn read(&self, reg: Register) -> u8 {
        match reg {
            Register::A => self.a,
            Register::B => self.b,
            Register::C => self.c,
            Register::D => self.d,
            Register::E => self.e,
            Register::F => self.f,
            Register::H => self.h,
            Register::L => self.l,
            Register::Flag => self.flag,
            _ => panic!("Register not available for 8-bit read"),
        }
    }

    fn read_u16(&self, reg: Register) -> u16 {
        match reg {
            Register::AF => (self.a as u16) << 8 | self.f as u16,
            Register::BC => (self.b as u16) << 8 | self.c as u16,
            Register::DE => (self.d as u16) << 8 | self.e as u16,
            Register::HL => (self.h as u16) << 8 | self.l as u16,
            Register::SP => self.sp,
            Register::PC => self.pc,
            _ => panic!("Register not available for 16-bit read"),
        }
    }

    fn write(&mut self, reg: Register, data: u8) {
        match reg {
            Register::A => self.a = data,
            Register::B => self.b = data,
            Register::C => self.c = data,
            Register::D => self.d = data,
            Register::E => self.e = data,
            Register::F => self.f = data,
            Register::H => self.h = data,
            Register::L => self.l = data,
            _ => panic!("Register not available for 8-bit write"),
        }
    }

    fn write_u16(&mut self, reg: Register, data: u16) {
        let (hi, lo) = ((data & 0xFF00 >> 8) as u8, (data & 0xFF) as u8);
        match reg {
            Register::AF => {
                self.a = hi;
                self.f = lo;
            },
            Register::BC => {
                self.b = hi;
                self.c = lo;
            },
            Register::DE => {
                self.d = hi;
                self.c = lo;
            },
            Register::HL => {
                self.h = hi;
                self.l = lo;
            },
            Register::SP => self.sp = data,
            Register::PC => self.pc = data,
            _ => panic!("Register not available for 16-bit write"),
        }
    }

    fn set_flag(&mut self, flag: RegFlag, on: bool) {
        let bit = match flag {
            RegFlag::Zero => 0x80,
            RegFlag::Subtract => 0x40,
            RegFlag::HalfCarry => 0x20,
            RegFlag::Carry => 0x10,
        };
        if (on) {
            self.flag |= bit;
        } else {
            self.flag &= bit ^ 0xFF;
        }
    }

    fn advance_pc(&mut self) -> u16 {
        let pc = self.pc;
        self.pc += 1;
        pc
    }

}

static GB_FREQUENCY: u32 = 4194304;

struct Cpu {
    reg: RegData,
    ram: AddressSpace,
    freq: u32,
    clock: u64,
    cycle_block: u32,
}

impl Cpu {

    fn new() -> Cpu {
        Cpu::new_with_freq(GB_FREQUENCY)
    }

    fn new_with_freq(freq: u32) -> Cpu {
        Cpu {
            reg: RegData::new(),
            ram: AddressSpace::new(),
            freq: freq,
            clock: 0,
            cycle_block: 0,
        }
    }

    fn do_cycle(&mut self) {
        self.clock += 1;
        if self.cycle_block > 0 {
            self.cycle_block -= 1;
        } else {
            let instr = Instr::parse(&mut self.reg, &self.ram);
            match instr.opcode() {
                _ => panic!("Instruction not implemented!"),
            }
        }
    }

}

fn main() {
    println!("Hello, world!");
}
<|endoftext|>


<commit_before>
extern crate mio;
extern crate byteorder;
extern crate slab;

mod server;
mod connection;
mod poll;
mod context;
mod serialize;

use std::thread;
use std::sync::Arc;
use std::io;
use serialize::MessageHandler;
use connection::Connection;

struct EchoHandler {
    //nop
}

impl EchoHandler {
    fn new() -> EchoHandler {
        EchoHandler {}
    }
}

impl MessageHandler for EchoHandler {
    fn on_message_received(&self, c: &Connection, message: &Arc<Vec<u8>>) -> io::Result<()> {
        c.send_message(message.clone());
        Ok(())
    }
}

fn main() {
    let s = context::ServerContext::new("127.0.0.1:7777", 127);

    if let Some(ctx) = s {
        let server = server::Server::new(EchoHandler::new());

        let mut handles = vec![];
        for _ in 0..3 {
            let clone = ctx.clone();
            let mut server_clone = server.clone();
            handles.push(thread::spawn(move || {
                                           server_clone.run(&clone).expect("server run failed");
                                       }));
        }

        for handle in handles {
            handle.join().unwrap();
        }

    }
    println!("app exit!");
}
<commit_msg>Update main.rs<commit_after>
extern crate mio;
extern crate byteorder;
extern crate slab;

mod server;
mod connection;
mod poll;
mod context;
mod serialize;

use std::thread;
use std::sync::Arc;
use std::io;
use serialize::MessageHandler;
use connection::Connection;

struct EchoHandler {
    //nop
}

impl EchoHandler {
    fn new() -> EchoHandler {
        EchoHandler {}
    }
}

impl MessageHandler for EchoHandler {
    fn on_message_received(&self, c: &Connection, message: &Arc<Vec<u8>>) -> io::Result<()> {
        c.send_message(message.clone());
        Ok(())
    }
}

/* main usage */
fn main() {
    let listener = context::bind("127.0.0.1:7777").unwrap();
    let context = context::Context::new(EchoHandler::new(), /* max clients */127);

    let mut handles = vec![];
    for _ in 0..3 {
        let mut server = server::Server::new(listener.try_clone().unwrap()).unwrap();
        let ctx = context.clone();
        handles.push(thread::spawn(move || {
            server.run::<EchoHandler>(&ctx).expect("server run failed");
        }));
    }

    for handle in handles {
        handle.join().unwrap();
    }
    println!("app exit!");
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate router;
extern crate mount;
extern crate staticfile;
extern crate robots;
extern crate persistent;
extern crate env_logger;

use iron::prelude::*;
use iron::status;
use router::Router;
use staticfile::Static;
use mount::Mount;
use std::path::Path;
use std::any::Any;
use std::sync::{Arc,Mutex};
use robots::actors::{ActorSystem,Actor,ActorCell,ActorContext,Props,ActorRef,ActorPath};
use persistent::Read;
use iron::typemap::Key;
use std::fmt::{Debug, Display,Formatter,Result};
use gpioaccess::PinProxy;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DirectionProxied {
    In,
    Out,
    High,
    Low,
}

#[derive(Debug)]
pub enum ProxyError {
	MonErreur,
}

impl ::std::error::Error for ProxyError {
	fn description(&self) -> &str {
		"an error"
	}
}

impl Display for ProxyError {
	fn fmt(&self, f: &mut Formatter) -> Result {
		write!(f, "an error")
	}
}

pub type ProxyResult<T> = ::std::result::Result<T, ProxyError>;

//depend on abstractions not concretions lulz
trait PinProxyContract {

	fn new(pin_num: u64) -> Self;
	//FIXME :figure out mapping overloaded Result from gpio library
	fn export(&self) -> ProxyResult<()>;

	fn unexport(&self) ->  ProxyResult<()>;

	fn set_value(&self, value: u8) -> ProxyResult<()>;

	fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>;
}

#[cfg(linux)]
pub mod gpioaccess{

	extern crate sysfs_gpio;
	use sysfs_gpio::{Direction, Pin};
	use super::{PinProxyContract,DirectionProxied,ProxyError,ProxyResult};

	pub struct PinProxy {
		pin : Pin,
	}

	impl PinProxyContract for PinProxy
	{
		fn new(pin_num: u64) -> PinProxy {
			PinProxy{ pin: Pin::new(pin_num) }
		}

		fn export(&self) ->  ProxyResult<()>{
			match self.pin.export()
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,

			}
		}

		fn unexport(&self) ->  ProxyResult<()> {
			match self.pin.unexport()
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,

			}
		}

		fn set_value(&self, value: u8) ->  ProxyResult<()> {
			match self.pin.set_value(value)
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,

			}
		}

		fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>{
			let dirmapped =  match dir {
                                           DirectionProxied::In =>  Direction::In,
                                           DirectionProxied::Out => Direction::Out,
                                           DirectionProxied::High => Direction::High,
                                           DirectionProxied::Low => Direction::Low,
                                       };
			match self.pin.set_direction(dirmapped)
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,

			}
		}

    }
}

#[cfg(not(linux))]
pub mod gpioaccess{

	use std::fmt;
	use super::{PinProxyContract,DirectionProxied,ProxyError,ProxyResult};

	pub struct PinProxy {
		pin_num: u64,
	}

	impl PinProxyContract for PinProxy
	{
		fn new(pin_num: u64) -> PinProxy {
			PinProxy{ pin_num: pin_num }
		}

		fn export(&self) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}

		fn unexport(&self) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}

		fn set_value(&self, value: u8) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}

		fn set_direction(&self, dir: DirectionProxied) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}
    }
}

#[derive(Copy, Clone)]
pub struct Sys;
impl Key for Sys { type Value = ActorSystem; }

struct Resolver;

impl Actor for Resolver {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<String>(message) {
            let future = context.identify_actor(*message, "resolver_request".to_owned());
            context.forward_result_to_future::<Option<ActorRef>>(future, context.sender());
			context.stop(context.actor_ref());
        }
    }
}

impl Resolver {
    fn new(_dummy: ()) -> Resolver {
        Resolver
    }
}

fn main() {
	env_logger::init().unwrap();
	let dragon_actor_system  = ActorSystem::new("dragon".to_owned());
	dragon_actor_system.spawn_threads(3);

	dragon_actor_system.actor_of(Props::new(Arc::new(Dragon::new),()), "gorynich".to_owned());

    // the router (for RESTfull actions)
	let mut router = Router::new();

	router.get("/wings", move_wings,"wings");
	router.get("/mouth", open_mouth,"mouth");
	router.get("/eyes", blink_eyes,"eyes");

	fn handle_command(req: &mut Request, dragon_command: DragonCommands, dragon_event: DragonEvents ) ->IronResult<Response> {
		let arcsys = req.get::<Read<Sys>>().unwrap();
    	let sys = arcsys.as_ref();
		let props = Props::new(Arc::new(Resolver::new), ());
    	let answerer = sys.actor_of(props.clone(), "answerer".to_owned());
        let dragon = sys.ask(answerer, "/user/gorynich".to_owned(), "future".to_owned());
    	let dragon: Option<ActorRef> = sys.extract_result(dragon);
		match dragon {
			None => {
				Ok(Response::with((status::Ok, "Dragon not found")))
			}
			Some(dragonunwrapped) => {
				let future = sys.ask(dragonunwrapped, dragon_command, "request".to_owned());
	    		let event: DragonEvents = sys.extract_result(future);
				if event == dragon_event {
					Ok(Response::with((status::Ok, dragon_event.to_string())))
				} else
				{
					Ok(Response::with((status::Ok, "Unknown event!")))
				}
			}
		}
	}

	fn move_wings(req:&mut Request)  -> IronResult<Response>  {
		handle_command(req,DragonCommands::MoveWings,DragonEvents::WingsMoved)
	}

	fn open_mouth(req: &mut Request) -> IronResult<Response> {
		handle_command(req,DragonCommands::OpenMouth,DragonEvents::MouthOpened)
	}

	fn blink_eyes(req: &mut Request) -> IronResult<Response> {
		handle_command(req,DragonCommands::BlinkEyes,DragonEvents::EyesBlinked)
	}

	let mut chain = Chain::new(router);
	chain.link(Read::<Sys>::both(dragon_actor_system));

	// the mounter for static files
	let mut mount = Mount::new();
	mount
		.mount("/",Static::new(Path::new("static")))
		.mount("/api/",chain);
	Iron::new(mount).http("0.0.0.0:8080").unwrap();
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum DragonCommands {
	MoveWings,
	OpenMouth,
	BlinkEyes,
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum DragonEvents {
	WingsMoved,
	MouthOpened,
	EyesBlinked,
}

impl Display for DragonCommands {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

impl Display for DragonEvents {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

struct Dragon;

impl Actor for Dragon {

	fn pre_start(&self, context: ActorCell) {
		let wings = context.actor_of(Props::new(Arc::new(Wings::new),()), "wings".to_owned()).unwrap();
		let mouth = context.actor_of(Props::new(Arc::new(Mouth::new),()), "mouth".to_owned()).unwrap();
		let eyes = context.actor_of(Props::new(Arc::new(Eyes::new),()), "eyes".to_owned()).unwrap();
		context.tell(wings,LimbCommands::Init(10));
		context.tell(mouth,LimbCommands::Init(10));
		context.tell(eyes,LimbCommands::Init(10));
	}
	fn receive(&self, _message: Box<Any>, _context: ActorCell){
		if let Ok(_message) = Box::<Any>::downcast::<DragonCommands>(_message){
			match *_message {
				DragonCommands::MoveWings => {
						let wings: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/wings".to_owned())).cloned().unwrap();
						_context.tell(wings,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::WingsMoved);
						},
				DragonCommands::OpenMouth => {
						let mouth: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/mouth".to_owned())).cloned().unwrap();
						_context.tell(mouth,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::MouthOpened);
						},
				DragonCommands::BlinkEyes => {
						let eyes: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/eyes".to_owned())).cloned().unwrap();
						_context.tell(eyes,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::EyesBlinked);
						}
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Dragon {
	fn new(_: ()) -> Dragon {
		Dragon
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum LimbCommands {
	Init(u64),
	Aggitate,
	Reset,
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum LimbEvents {
	Aggitated,
	NotAggitated(u64),
}

impl Display for LimbCommands {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

impl Display for LimbEvents {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

struct Wings;

impl Actor for Wings {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
						println!("Moving Wings");
						//_context.complete(_context.sender(),LimbEvents::Aggitated);
						},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Wings {
    fn new(_: ()) -> Wings {
        Wings
    }
}

struct Mouth;

impl Actor for Mouth {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
						println!("Opening Mouth");
						//_context.complete(_context.sender(),LimbEvents::Aggitated);
						},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Mouth {
    fn new(_: ()) -> Mouth {
        Mouth
    }
}

struct Eyes;

impl Actor for Eyes {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
						println!("Blinking Eyes");
						//_context.complete(_context.sender(),LimbEvents::Aggitated);
						},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Eyes {
    fn new(_: ()) -> Eyes {
        Eyes
    }
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum PinCommands {
	Blink(u64),
	Switch,
}

struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				PinCommands::Blink(times) => { },
				PinCommands::Switch => {	}
			}
		}
	}
}

impl PinActor{
	fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
    }
}

mod test;
<commit_msg>bridge to pin<commit_after>extern crate iron;
extern crate router;
extern crate mount;
extern crate staticfile;
extern crate robots;
extern crate persistent;
extern crate env_logger;

use iron::prelude::*;
use iron::status;
use router::Router;
use staticfile::Static;
use mount::Mount;
use std::path::Path;
use std::any::Any;
use std::sync::{Arc,Mutex};
use robots::actors::{ActorSystem,Actor,ActorCell,ActorContext,Props,ActorRef,ActorPath};
use persistent::Read;
use iron::typemap::Key;
use std::fmt::{Debug, Display,Formatter,Result};
use gpioaccess::PinProxy;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DirectionProxied {
    In,
    Out,
    High,
    Low,
}

#[derive(Debug)]
pub enum ProxyError {
	MonErreur,
}

impl ::std::error::Error for ProxyError {
	fn description(&self) -> &str {
		"an error"
	}
}

impl Display for ProxyError {
	fn fmt(&self, f: &mut Formatter) -> Result {
		write!(f, "an error")
	}
}

pub type ProxyResult<T> = ::std::result::Result<T, ProxyError>;

//depend on abstractions not concretions lulz
trait PinProxyContract {

	fn new(pin_num: u64) -> Self;
	//FIXME :figure out mapping overloaded Result from gpio library
	fn export(&self) -> ProxyResult<()>;

	fn unexport(&self) ->  ProxyResult<()>;

	fn set_value(&self, value: u8) -> ProxyResult<()>;

	fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>;
}

#[cfg(linux)]
pub mod gpioaccess{

	extern crate sysfs_gpio;
	use sysfs_gpio::{Direction, Pin};
	use super::{PinProxyContract,DirectionProxied,ProxyError,ProxyResult};

	pub struct PinProxy {
		pin : Pin,
	}

	impl PinProxyContract for PinProxy
	{
		fn new(pin_num: u64) -> PinProxy {
			PinProxy{ pin: Pin::new(pin_num) }
		}

		fn export(&self) ->  ProxyResult<()>{
			match self.pin.export()
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,

			}
		}

		fn unexport(&self) ->  ProxyResult<()> {
			match self.pin.unexport()
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,
			}
		}

		fn set_value(&self, value: u8) ->  ProxyResult<()> {
			match self.pin.set_value(value)
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,
			}
		}

		fn set_direction(&self, dir: DirectionProxied) ->  ProxyResult<()>{
			let dirmapped =  match dir {
                                           DirectionProxied::In =>  Direction::In,
                                           DirectionProxied::Out => Direction::Out,
                                           DirectionProxied::High => Direction::High,
                                           DirectionProxied::Low => Direction::Low,
                                       };
			match self.pin.set_direction(dirmapped)
			{
				Ok(()) => Ok(()),
				_ => ProxyError::MonErreur,
			}
		}

    }
}

#[cfg(not(linux))]
pub mod gpioaccess{
	use std::fmt;
	use super::{PinProxyContract,DirectionProxied,ProxyError,ProxyResult};

	pub struct PinProxy {
		pin_num: u64,
	}

	impl PinProxyContract for PinProxy
	{
		fn new(pin_num: u64) -> PinProxy {
			PinProxy{ pin_num: pin_num }
		}
		fn export(&self) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}
		fn unexport(&self) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}

		fn set_value(&self, value: u8) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}

		fn set_direction(&self, dir: DirectionProxied) -> ProxyResult<()>
		{
			Ok::<(),ProxyError>(())
		}
    }
}

#[derive(Copy, Clone)]
pub struct Sys;
impl Key for Sys { type Value = ActorSystem; }

struct Resolver;

impl Actor for Resolver {
    fn receive(&self, message: Box<Any>, context: ActorCell) {
        if let Ok(message) = Box::<Any>::downcast::<String>(message) {
            let future = context.identify_actor(*message, "resolver_request".to_owned());
            context.forward_result_to_future::<Option<ActorRef>>(future, context.sender());
			context.stop(context.actor_ref());
        }
    }
}

impl Resolver {
    fn new(_dummy: ()) -> Resolver {
        Resolver
    }
}

fn main() {
	env_logger::init().unwrap();
	let dragon_actor_system  = ActorSystem::new("dragon".to_owned());
	dragon_actor_system.spawn_threads(3);

	dragon_actor_system.actor_of(Props::new(Arc::new(Dragon::new),()), "gorynich".to_owned());
    // the router (for RESTfull actions)
	let mut router = Router::new();
	router.get("/wings", move_wings,"wings");
	router.get("/mouth", open_mouth,"mouth");
	router.get("/eyes", blink_eyes,"eyes");

	fn handle_command(req: &mut Request, dragon_command: DragonCommands, dragon_event: DragonEvents ) ->IronResult<Response> {
		let arcsys = req.get::<Read<Sys>>().unwrap();
    	let sys = arcsys.as_ref();
		let props = Props::new(Arc::new(Resolver::new), ());
    	let answerer = sys.actor_of(props.clone(), "answerer".to_owned());
        let dragon = sys.ask(answerer, "/user/gorynich".to_owned(), "future".to_owned());
    	let dragon: Option<ActorRef> = sys.extract_result(dragon);
		match dragon {
			None => {
				Ok(Response::with((status::Ok, "Dragon not found")))
			}
			Some(dragonunwrapped) => {
				let future = sys.ask(dragonunwrapped, dragon_command, "request".to_owned());
	    		let event: DragonEvents = sys.extract_result(future);
				if event == dragon_event {
					Ok(Response::with((status::Ok, dragon_event.to_string())))
				} else
				{
					Ok(Response::with((status::Ok, "Unknown event!")))
				}
			}
		}
	}

	fn move_wings(req:&mut Request)  -> IronResult<Response>  {
		handle_command(req,DragonCommands::MoveWings,DragonEvents::WingsMoved)
	}

	fn open_mouth(req: &mut Request) -> IronResult<Response> {
		handle_command(req,DragonCommands::OpenMouth,DragonEvents::MouthOpened)
	}

	fn blink_eyes(req: &mut Request) -> IronResult<Response> {
		handle_command(req,DragonCommands::BlinkEyes,DragonEvents::EyesBlinked)
	}

	let mut chain = Chain::new(router);
	chain.link(Read::<Sys>::both(dragon_actor_system));
	// the mounter for static files
	let mut mount = Mount::new();
	mount
		.mount("/",Static::new(Path::new("static")))
		.mount("/api/",chain);
	Iron::new(mount).http("0.0.0.0:8080").unwrap();
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum DragonCommands {
	MoveWings,
	OpenMouth,
	BlinkEyes,
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum DragonEvents {
	WingsMoved,
	MouthOpened,
	EyesBlinked,
}

impl Display for DragonCommands {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

impl Display for DragonEvents {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

struct Dragon;

impl Actor for Dragon {

	fn pre_start(&self, context: ActorCell) {
		let wings = context.actor_of(Props::new(Arc::new(Wings::new),()), "wings".to_owned()).unwrap();
		let mouth = context.actor_of(Props::new(Arc::new(Mouth::new),()), "mouth".to_owned()).unwrap();
		let eyes = context.actor_of(Props::new(Arc::new(Eyes::new),()), "eyes".to_owned()).unwrap();
		context.tell(wings,LimbCommands::Init(10));
		context.tell(mouth,LimbCommands::Init(10));
		context.tell(eyes,LimbCommands::Init(10));
	}
	fn receive(&self, _message: Box<Any>, _context: ActorCell){
		if let Ok(_message) = Box::<Any>::downcast::<DragonCommands>(_message){
			match *_message {
				DragonCommands::MoveWings => {
						let wings: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/wings".to_owned())).cloned().unwrap();
						_context.tell(wings,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::WingsMoved);
						},
				DragonCommands::OpenMouth => {
						let mouth: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/mouth".to_owned())).cloned().unwrap();
						_context.tell(mouth,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::MouthOpened);
						},
				DragonCommands::BlinkEyes => {
						let eyes: ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/eyes".to_owned())).cloned().unwrap();
						_context.tell(eyes,LimbCommands::Aggitate);
						_context.complete(_context.sender(),DragonEvents::EyesBlinked);
						}
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Dragon {
	fn new(_: ()) -> Dragon {
		Dragon
	}
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum LimbCommands {
	Init(u64),
	Aggitate,
	Reset,
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum LimbEvents {
	Aggitated,
	NotAggitated(u64),
}

impl Display for LimbCommands {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

impl Display for LimbEvents {
    fn fmt(&self, f: &mut Formatter) -> Result {
        Debug::fmt(self, f)
    }
}

struct Wings;

impl Actor for Wings {
    fn pre_start(&self, context: ActorCell) {
		   context.actor_of(Props::new(Arc::new(PinActor::new), 18), "pin18".to_owned()).unwrap();
    }
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
            let pin18 : ActorRef = _context.children().get(&ActorPath::new_local("/user/gorynich/wings/pin18".to_owned())).cloned().unwrap();
						_context.tell(pin18,PinCommands::Blink(20));
						println!("Moving Wings");
				},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Wings {
    fn new(_: ()) -> Wings {
        Wings
    }
}

struct Mouth;

impl Actor for Mouth {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
						println!("Opening Mouth");
						},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Mouth {
    fn new(_: ()) -> Mouth {
        Mouth
    }
}

struct Eyes;

impl Actor for Eyes {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<LimbCommands>(_message){
			match *_message {
				LimbCommands::Init(max) => { println!("Initializing with maximum {}",max); },
				LimbCommands::Aggitate => {
						println!("Blinking Eyes");
						//_context.complete(_context.sender(),LimbEvents::Aggitated);
						},
				LimbCommands::Reset => { println!("Received reset"); }
			}
		} else {
			println!("Gorynich does not understand!");
		}
	}
}

impl Eyes {
    fn new(_: ()) -> Eyes {
        Eyes
    }
}

#[derive(Copy, Clone, PartialEq,Debug)]
enum PinCommands {
	Blink(u64),
	Switch,
}

struct PinActor {
	pinproxy :  Mutex<PinProxy>,
}

impl Actor for PinActor {
    fn receive(&self, _message: Box<Any>, _context: ActorCell) {
		if let Ok(_message) = Box::<Any>::downcast::<PinCommands>(_message){
			match *_message {
				  PinCommands::Blink(times) => {
              let pin = self.pinproxy.lock().unwrap();
          },
				PinCommands::Switch => {	}
			}
		}
	}
}

impl PinActor{
	fn new(pin_number: u64) -> PinActor {
		PinActor{ pinproxy : Mutex::new(PinProxy::new(pin_number)) }
    }
}

mod test;
<|endoftext|>


<commit_before>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, Read};
use std::fs::File;
use std::process::exit;
use std::time::Instant;

use clap::{Arg, App};

use ppbert::bertterm::{
    self,
    BertTerm,
    DEFAULT_INDENT_WIDTH,
    DEFAULT_MAX_TERMS_PER_LINE
};
use ppbert::error::Result;
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("--indent-width")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("--max-terms-per-line")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("--verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("--parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };

    let indent_level = value_t!(matches, "indent_width", usize)
        .unwrap_or(DEFAULT_INDENT_WIDTH);
    let max_per_line = value_t!(matches, "max_per_line", usize)
        .unwrap_or(DEFAULT_MAX_TERMS_PER_LINE);
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");

    let transform_proplists = matches.is_present("transform-proplists");
    let parse_fn = if matches.is_present("bert2") { parse_bert2 } else { parse_bert1 };
    let output_fn =
        if matches.is_present("json") {
            if transform_proplists {
                bertterm::pp_json_proplist
            } else {
                bertterm::pp_json
            }
        } else {
            if transform_proplists {
                eprintln!("{}: warning: --transform-proplists is only valid with the --json flag",
                          PROG_NAME);
            }
            bertterm::pp_bert
        };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(e) => {
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn handle_file<T>(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(Vec<u8>) -> Result<T>,
    pp_fn: fn(T, usize, usize) -> ()
) -> Result<()> {

    // Read file or stdin into buffer
    let mut buf: Vec<u8> = Vec::new();
    let now = Instant::now();
    if file == "-" {
        let mut stdin = io::stdin();
        stdin.read_to_end(&mut buf)?;
    } else {
        let mut f = File::open(file)?;
        f.read_to_end(&mut buf)?;
    }
    let dur0 = now.elapsed();
    if verbose {
        eprintln!("{}: read time: {}.{:09}",
                  PROG_NAME, dur0.as_secs(), dur0.subsec_nanos());
    }

    // Parse input
    let now = Instant::now();
    let parse_output = parse_fn(buf)?;
    let dur1 = now.elapsed();

    if verbose {
        eprintln!("{}: parse time: {}.{:09}",
                  PROG_NAME, dur1.as_secs(), dur1.subsec_nanos());
    }

    // Early exit if parse-only
    if parse_only {
        return Ok(());
    }

    // Pretty print
    let now = Instant::now();
    pp_fn(parse_output, indent, terms_per_line);
    let dur2 = now.elapsed();

    if verbose {
        eprintln!("{}: print time: {}.{:09}",
                  PROG_NAME, dur2.as_secs(), dur2.subsec_nanos());
    }

    return Ok(());
}

fn parse_bert1(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    let term = parser.parse()?;
    return Ok(vec![term]);
}

fn parse_bert2(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    return parser.parse_bert2();
}
<commit_msg>Buffer input when reading<commit_after>extern crate ppbert;
#[macro_use] extern crate clap;

use std::io::{self, BufReader, Read};
use std::fs::File;
use std::process::exit;
use std::time::Instant;

use clap::{Arg, App};

use ppbert::bertterm::{
    self,
    BertTerm,
    DEFAULT_INDENT_WIDTH,
    DEFAULT_MAX_TERMS_PER_LINE
};
use ppbert::error::Result;
use ppbert::parser;

const PROG_NAME: &str = "ppbert";

fn main() {
    let matches = App::new(PROG_NAME)
        .version(crate_version!())
        .author("Vincent Foley")
        .about("Pretty print structure encoded in Erlang's External Term Format")
        .arg(Arg::with_name("input_files")
             .value_name("FILES")
             .multiple(true))
        .arg(Arg::with_name("indent_width")
             .help("Indents with <num> spaces")
             .value_name("num")
             .short("i")
             .long("--indent-width")
             .takes_value(true))
        .arg(Arg::with_name("max_per_line")
             .help("Prints at most <num> basic terms per line")
             .value_name("num")
             .short("m")
             .long("--max-terms-per-line")
             .takes_value(true))
        .arg(Arg::with_name("verbose")
             .help("Enables verbose mode")
             .short("v")
             .long("--verbose"))
        .arg(Arg::with_name("parse")
             .help("Parses the input, doesn't pretty print it")
             .short("p")
             .long("--parse"))
        .arg(Arg::with_name("bert2")
             .help("Parses .bert2 files")
             .short("2")
             .long("bert2"))
        .arg(Arg::with_name("json")
             .help("Outputs in JSON")
             .short("j")
             .long("json"))
        .arg(Arg::with_name("transform-proplists")
             .help("Transforms proplists into JSON objects (only valid with --json)")
             .long("transform-proplists"))
        .get_matches();

    let files: Vec<&str> = match matches.values_of("input_files") {
        Some(files) => files.collect(),
        None => vec!["-"]
    };

    let indent_level = value_t!(matches, "indent_width", usize)
        .unwrap_or(DEFAULT_INDENT_WIDTH);
    let max_per_line = value_t!(matches, "max_per_line", usize)
        .unwrap_or(DEFAULT_MAX_TERMS_PER_LINE);
    let verbose = matches.is_present("verbose");
    let parse_only = matches.is_present("parse");

    let transform_proplists = matches.is_present("transform-proplists");
    let parse_fn = if matches.is_present("bert2") { parse_bert2 } else { parse_bert1 };
    let output_fn =
        if matches.is_present("json") {
            if transform_proplists {
                bertterm::pp_json_proplist
            } else {
                bertterm::pp_json
            }
        } else {
            if transform_proplists {
                eprintln!("{}: warning: --transform-proplists is only valid with the --json flag",
                          PROG_NAME);
            }
            bertterm::pp_bert
        };

    let mut return_code = 0;
    for file in files {
        let res = handle_file(file, parse_only, verbose,
                              indent_level, max_per_line,
                              parse_fn, output_fn);
        match res {
            Ok(()) => (),
            Err(e) => {
                return_code = 1;
                eprintln!("{}: {}: {}", PROG_NAME, file, e);
            }
        }
    }
    exit(return_code);
}

fn handle_file<T>(
    file: &str,
    parse_only: bool,
    verbose: bool,
    indent: usize,
    terms_per_line: usize,
    parse_fn: fn(Vec<u8>) -> Result<T>,
    pp_fn: fn(T, usize, usize) -> ()
) -> Result<()> {

    // Read file or stdin into buffer
    let mut buf: Vec<u8> = Vec::new();
    let now = Instant::now();
    if file == "-" {
        let stdin = io::stdin();
        let mut stdin = stdin.lock();
        stdin.read_to_end(&mut buf)?;
    } else {
        let f = File::open(file)?;
        let mut rdr = BufReader::new(f);
        rdr.read_to_end(&mut buf)?;
    }
    let dur0 = now.elapsed();
    if verbose {
        eprintln!("{}: read time: {}.{:09}",
                  PROG_NAME, dur0.as_secs(), dur0.subsec_nanos());
    }

    // Parse input
    let now = Instant::now();
    let parse_output = parse_fn(buf)?;
    let dur1 = now.elapsed();

    if verbose {
        eprintln!("{}: parse time: {}.{:09}",
                  PROG_NAME, dur1.as_secs(), dur1.subsec_nanos());
    }

    // Early exit if parse-only
    if parse_only {
        return Ok(());
    }

    // Pretty print
    let now = Instant::now();
    pp_fn(parse_output, indent, terms_per_line);
    let dur2 = now.elapsed();

    if verbose {
        eprintln!("{}: print time: {}.{:09}",
                  PROG_NAME, dur2.as_secs(), dur2.subsec_nanos());
    }

    return Ok(());
}

fn parse_bert1(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    let term = parser.parse()?;
    return Ok(vec![term]);
}

fn parse_bert2(buf: Vec<u8>) -> Result<Vec<BertTerm>> {
    let mut parser = parser::Parser::new(buf);
    return parser.parse_bert2();
}
<|endoftext|>


<commit_before>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use std::num::from_str_radix;

use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn parse_num(s: &str) -> Option<u32> {
    if s.slice_to(2) == "0x" {
        from_str_radix(s.slice_from(2), 16)
    } else {
        from_str_radix(s, 10)
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    let mut registers: Vec<_> = peripheral.registers.iter().collect();

    registers.as_mut_slice().sort_by(|a, b| {
        let a = a.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        let b = b.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        a.cmp(&b)
    });

    println!("ioregs!({} = {{", peripheral.name);
    for &register in registers.iter() {
        write_register(register);
    }
    println!("}}")
}

fn write_register(register: &Register) {
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    write_device(&device);
}
<commit_msg>Put dimension/increment in a comment, since it is handled differently by ioreg<commit_after>#![feature(globs)]
#![feature(macro_rules)]

extern crate xml;

use std::io::{File, BufferedReader};
use std::default::Default;
use std::num::from_str_radix;

use xml::reader::EventReader;
use fromxml::{parse_root};

mod fromxml;

deriving_fromxml! {
    struct Device {
        vendor:Option<String>,
        vendorID:Option<String>,
        licenseText:Option<String>,
        series:Option<String>,
        version:Option<String>,
        description:Option<String>,
        cpu:Option<CPU>,
        peripherals: Vec<Peripheral>,
    }

    struct Peripheral {
        name: String,
        version:Option<String>,
        description:Option<String>,
        groupName:Option<String>,
        prependToName:Option<String>,
        baseAddress:Option<String>,
        access:Option<String>,
        interrupt:Option<Interrupt>,
        registers: Vec<Register>,
    }

    struct Interrupt {
        name: String,
        value:Option<uint>,
    }

    struct Register {
        name: String,
        dim:Option<uint>,
        dimIncrement:Option<String>,
        description:Option<String>,
        addressOffset:Option<String>,
        size:Option<uint>,
        access:Option<String>,
        fields: Vec<Field>,
    }

    struct Field {
        name: String,
        description:Option<String>,
        bitOffset:Option<uint>,
        bitWidth:Option<uint>,
        access:Option<String>,
        enumeratedValues: Vec<EnumeratedValue>,
    }

    struct EnumeratedValue {
        name: String,
        value: String,
        description:Option<String>,
    }

    struct CPU {
        name:Option<String>,
        revision:Option<String>,
    }
}

fn parse_num(s: &str) -> Option<u32> {
    if s.slice_to(2) == "0x" {
        from_str_radix(s.slice_from(2), 16)
    } else {
        from_str_radix(s, 10)
    }
}

fn write_doc_comment(doc: Option<&String>) {
    if let Some(d) = doc {
        print!(" //= {}", d);
    }
}

fn write_device(device: &Device) {
    for peripheral in device.peripherals.iter() {
        write_peripheral(peripheral);
    }
}

fn write_peripheral(peripheral: &Peripheral) {
    let mut registers: Vec<_> = peripheral.registers.iter().collect();

    registers.as_mut_slice().sort_by(|a, b| {
        let a = a.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        let b = b.addressOffset.as_ref().map(|x| parse_num(x.as_slice()));
        a.cmp(&b)
    });

    println!("ioregs!({} = {{", peripheral.name);
    for &register in registers.iter() {
        write_register(register);
    }
    println!("}}")
}

fn write_register(register: &Register) {
    if let (Some(dim), Some(dim_increment)) = (register.dim, register.dimIncrement.as_ref()) {
        println!("    // repeat: {} increment {}", dim, dim_increment);
    }
    let offset = register.addressOffset.as_ref().map_or("", |x| x.as_slice());
    let size = register.size.unwrap_or(0);
    print!("    {} => reg{} {} {{", offset, size, register.name);
    write_doc_comment(register.description.as_ref());
    print!("\n");

    for field in register.fields.iter() {
        write_field(field);
    }
    println!("    }}");
}

fn write_field(field: &Field) {
    let lsb = field.bitOffset.unwrap();
    let width = field.bitWidth.unwrap();

    print!("         {}", lsb);

    if width > 1 {
        print!("..{}", lsb + width - 1);
    }

    print!(" => {}", field.name);

    if field.enumeratedValues.len() == 0 {
        print!(",");
    } else {
        print!(" {{");
    }

    write_doc_comment(field.description.as_ref());
    print!("\n");

    if field.enumeratedValues.len() != 0 {
        for en in field.enumeratedValues.iter() {
            if en.name.len() == 0 { continue } // TODO: this is a <name>, not an <enumeratedValues>
            print!("             {} => {}", en.name, en.value);
            write_doc_comment(en.description.as_ref());
            print!("\n");
        }
        println!("         }}");
    }
}

fn main() {
    let file = File::open(&Path::new("file.xml")).unwrap();
    let reader = BufferedReader::new(file);

    let mut parser = EventReader::new(reader);
    let mut iter = parser.events();
    let device: Device = parse_root(&mut iter).unwrap();

    write_device(&device);
}
<|endoftext|>


<commit_before>extern crate regex;
extern crate getopts;
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::{env, fs, io};
use std::io::prelude::*;
mod options;
use options::*;
use std::process;
use std::collections::hash_map::Entry::{Occupied, Vacant};

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
    );

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const KEY_FILE: &'static str = "KEY_FILE";
const ENV: &'static str = "ENV";
const MISSING: &'static str = "Missing properties";

fn replace_var(line: String,
               keys: &Option<KeysAndSources>,
               props_first: bool,
               used_keys: &mut HashMap<String, Vec<(String, String)>>,
               result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>[^\}]*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var")
           .map(|v| {
               let env_prop = env_or_prop(v.trim(), props_first, keys)
                                  .map(|v2| {
                                      str_line = re.replace(&*str_line,
                                                            &*(v2.1.value));
                                      println!("{:?}", v2);
                                      (v2.0, v2.1)
                                  });

               env_prop.and_then(|v2| {
                   used_keys.get_mut(&v2.1.source)
                            .and_then(|r| {
                                println!("r: {:?}", r);
                                println!("v2: {:?}", v2);
                                Some(r.push((v2.0.clone(), v2.1.value.clone())))
                            })
                            .or_else(|| {
                                used_keys.insert(v2.1.source.clone(),
                                                 vec![(v2.0.clone(),
                                                       v2.1.value.clone())]);
                                Some(())
                            })
               })
           });
    }
    result.push(str_line.to_string());
}

fn env_or_prop(key: &str,
               props_first: bool,
               keys: &Option<KeysAndSources>)
               -> Option<(String, ValueAndSource)> {
    match keys {
        &Some(ref k) => {
            let dict = &(k.dictionary);
            let prop = dict.get(key).and_then(|v| Some(v.clone()));
            let env = env::var_os(key)
                          .map(|v2| v2.clone().into_string().ok().unwrap());
            match (prop, props_first) {
                (Some(prop), true) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: prop.value.clone(),
                        source: prop.source.clone(),
                    }))
                }
                (Some(prop), false) => {
                    match env {
                        Some(e) => {
                            println!("[WARNING]: key \"${{{}}}\" from the \
                                      file \"{}\" was overridden by an \
                                      environment variable with the same \
                                      name.",
                                     key.to_string(),
                                     prop.source);
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: prop.value.clone(),
                                source: prop.source.clone(),
                            }))
                        }
                    }
                }
                (None, true) => {
                    match env {
                        Some(e) => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: key.to_string(),
                                source: MISSING.to_string(),
                            }))
                        }
                    }
                }
                (None, false) => {
                    match env {
                        Some(e) => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: key.to_string(),
                                source: MISSING.to_string(),
                            }))
                        }
                    }
                }
            }
        }
        &None => {
            match env::var_os(key)
                      .map(|v| v.into_string().ok())
                      .unwrap_or(None) {
                Some(e) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: e.to_string(),
                        source: ENV.to_string(),
                    }))
                }
                None => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: key.to_string(),
                        source: MISSING.to_string(),
                    }))
                }
            }
        }
    }
}

fn process(file: fs::File,
           used_keys: &mut HashMap<String, Vec<(String, String)>>,
           dict: &Option<KeysAndSources>,
           props_first: bool)
           -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec![];

    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, props_first, used_keys, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String> {
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut keys = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1
                                                 .ok()
                                                 .expect("Could not read \
                                                          line")) {
            let key = cap.name("key")
                         .unwrap_or("???");
            let val = cap.name("val")
                         .unwrap_or("???");
            if !keys.contains_key(key) {
                keys.insert(key.to_string(), val.to_string());
            }
        }
    }

    keys
}

#[derive(Debug)]
#[derive(Clone)]
struct ValueAndSource {
    value: String,
    source: String,
}

fn insert_if_not_exist(dict: &mut HashMap<String, ValueAndSource>,
                       keys_from_files: &mut HashMap<String, Vec<String>>,
                       matches: HashMap<String, String>,
                       filename: String) {
    for key_val in matches.iter() {
        let key: String = (*key_val.0).clone();
        let val: String = (*key_val.1).clone();
        match dict.entry(key.clone()) {
            Vacant(e) => {
                e.insert(ValueAndSource {
                    value: val,
                    source: filename.clone(),
                });
                match keys_from_files.entry(filename.clone()) {
                    Vacant(k) => {
                        k.insert(vec![key.clone()]);
                    }
                    Occupied(mut k) => {
                        k.get_mut().push(key.clone());
                    }
                }

                // keys_from_files.insert(filename.clone(), key.clone());
            }
            Occupied(e) => {
                println!("[ERROR]: key ({}) in file ({}) tried to override the \
                          same key from file ({})",
                         key,
                         filename,
                         e.get().source);
                process::exit(1);
            }
        }
    }
}

fn read_keyfiles_to_dict(key_filenames: Vec<String>) -> Option<KeysAndSources> {
    let mut dict: HashMap<String, ValueAndSource> = HashMap::new();
    let mut keys_from_files = HashMap::new();
    for filename in key_filenames {
        fs::File::open(&filename)
            .and_then(|f| Ok(extract_keys(f)))
            .map(|v| {
                insert_if_not_exist(&mut dict,
                                    &mut keys_from_files,
                                    v,
                                    filename);
            });
    }

    match dict.len() {
        0 => None,
        _ => {
            Some(KeysAndSources {
                dictionary: Box::new(dict),
                sources: Box::new(keys_from_files),
            })
        }
    }
}

fn create_file(filename: &String) -> fs::File {
    match fs::File::create(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not create file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

fn open_file(filename: &String) -> fs::File {
    match fs::File::open(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not open file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

struct Settings<'a> {
    key_filenames: Vec<String>,
    prop_filename: &'a String,
    result_filename: &'a String,
    props_first: bool,
}

struct KeysAndSources {
    dictionary: Box<HashMap<String, ValueAndSource>>,
    sources: Box<HashMap<String, Vec<String>>>,
}

fn calc_result(settings: Settings) {
    let prop_file = open_file(&settings.prop_filename);
    let mut result_buff = Vec::new();
    let mut used_keys = HashMap::new();
    let keys_and_sources = read_keyfiles_to_dict(settings.key_filenames);

    let processed_buffer = process(prop_file,
                                   &mut used_keys,
                                   &keys_and_sources,
                                   settings.props_first);

    for line in processed_buffer.iter() {
        result_buff.push(line.clone());
    }

    println!("======== RESULTS ========");

    let env_vars = &used_keys.remove(ENV);
    if env_vars.is_some() {
        let vars = env_vars.clone().unwrap();
        println!("# Environment variables:");
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
    }

    for src in used_keys.iter() {
        println!("# {}:", src.0);
        let mut keys_src = src.1.clone();
        keys_src.sort();
        for s in keys_src {
            println!("${{{}}}", s.0);
        }
        println!("");
    }

    let missing_vars = used_keys.get(MISSING);
    if missing_vars.is_some() {
        let vars = missing_vars.unwrap();
        println!("Missing variables found in {}:", settings.prop_filename);
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
        println_stderr!("ERROR: Must replace all found variables\n\n");
        process::exit(1);
    }

    if env_vars.is_none() && used_keys.len() == 0 && missing_vars.is_none() {
       println!("[No variables to substitute!]\n");
    }

    let mut result_file = create_file(settings.result_filename);

    for line in result_buff {
        result_file.write_all(&format!("{}\n", line).as_bytes()).unwrap();
    }
    result_file.flush().unwrap();

    println!("...DONE!");
}

fn get_arg_parser() -> ApplicationOptions {
    ApplicationOptions::new(|| {
        let mut o = OptionsAndFlags::new();
        o.parsing_style(getopts::ParsingStyle::StopAtFirstFree);
        o.opt("k",
              "keys",
              "keyfile(s) with variable substitutions, can occur multiple \
               times",
              "FILE(s)",
              getopts::HasArg::Yes,
              getopts::Occur::Multi)
         .unwrap();
        o.opt("p",
              "props-first",
              "properties takes precedence over environment variables \
               (default: off)",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("?",
              "help",
              "print this help menu",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("V",
              "version",
              "prints current version number",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        Ok(o)
    })
}

struct PropAndResultFilenames<'a> {
    prop_filename: &'a String,
    result_filename: &'a String,
}

fn get_prop_and_result_filename<'a>(free_args: &'a Vec<String>)
                                    -> PropAndResultFilenames<'a> {
    match free_args.len() {
        1 => {
            // Replace vars in the provided file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[0],
            }
        }
        2 => {
            // Replace vars into a separate output file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[1],
            }
        }
        _ => {
            println_stderr!("Wrong number of file parameters: {}",
                            free_args.len());
            APP.print_usage();
            process::exit(1);
        }
    }
}

fn get_props_first(matches: &Box<getopts::Matches>) -> bool {
    if matches.opt_present("p") {
        true
    } else {
        false
    }

}

fn get_parsed_args() -> Box<getopts::Matches> {
    Box::new(APP.parse().unwrap_or_else(|e| {
        println_stderr!("{}", e);
        process::exit(1);
    }))
}

// Singletons
lazy_static! {
    static ref APP: ApplicationOptions = get_arg_parser();
}

#[allow(dead_code)]
fn main() {
    let matches = get_parsed_args();

    if matches.opt_present("V") {
        println!("proper: v{}", VERSION);
        process::exit(0);
    }

    let prop_and_result_filenames = get_prop_and_result_filename(&matches.free);
    calc_result(Settings {
        key_filenames: matches.opt_strs("k"),
        prop_filename: prop_and_result_filenames.prop_filename,
        result_filename: prop_and_result_filenames.result_filename,
        props_first: get_props_first(&matches),
    });
}

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

    struct TestData {
        key_map: HashMap<String, ValueAndSource>,
        used_keys: HashMap<&'static str, Vec<(String, String)>>,
        result: Vec<String>,
    }

    fn create_test_data(keys: Vec<(&str, &str)>) -> TestData {
        let mut test_data = TestData {
            key_map: HashMap::new(),
            used_keys: HashMap::new(),
            result: Vec::new(),
        };

        for k in keys {
            test_data.key_map.insert(k.0.to_string(),
                                     ValueAndSource {
                                         value: k.1.to_string(),
                                         source: "".to_string(),
                                     });
        }

        test_data
    }

    #[test]
    fn can_sub_single_var() {
        let mut test_data = create_test_data(vec![("val", "world!")]);
        replace_var("Hello ${val}".to_string(),
                    &Some(test_data.key_map),
                    true,
                    &mut test_data.used_keys,
                    &mut test_data.result);
        assert!(test_data.result.len() == 1);
        assert!(test_data.used_keys[super::KEY_FILE][0].0 == "val".to_string());
        assert!(test_data.result[0] == "Hello world!".to_string());
    }
}
<commit_msg>Removed some debug printout and extracted the printing of the result from the calculate result function<commit_after>extern crate regex;
extern crate getopts;
#[macro_use]
extern crate lazy_static;
use std::collections::HashMap;
use std::{env, fs, io};
use std::io::prelude::*;
mod options;
use options::*;
use std::process;
use std::collections::hash_map::Entry::{Occupied, Vacant};

macro_rules! regex { ($re:expr) => { ::regex::Regex::new($re).unwrap() } }
macro_rules! println_stderr(
    ($($arg:tt)*) => (
        match writeln!(&mut ::std::io::stderr(), $($arg)* ) {
            Ok(_) => {},
            Err(x) => panic!("Unable to write to stderr: {}", x),
        }
        )
    );

const VERSION: &'static str = env!("CARGO_PKG_VERSION");
const KEY_FILE: &'static str = "KEY_FILE";
const ENV: &'static str = "ENV";
const MISSING: &'static str = "Missing properties";

fn replace_var(line: String,
               keys: &Option<KeysAndSources>,
               props_first: bool,
               used_keys: &mut HashMap<String, Vec<(String, String)>>,
               result: &mut Vec<String>) {
    let re = regex!(r"(?P<full>\$\{\s*(?P<var>[^\}]*)\s*\})");
    let mut str_line: String = line.clone();

    for cap in re.captures_iter(&*str_line.clone()) {
        cap.name("var")
           .map(|v| {
               let env_prop = env_or_prop(v.trim(), props_first, keys)
                                  .map(|v2| {
                                      str_line = re.replace(&*str_line,
                                                            &*(v2.1.value));
                                      (v2.0, v2.1)
                                  });

               env_prop.and_then(|v2| {
                   used_keys.get_mut(&v2.1.source)
                            .and_then(|r| {
                                Some(r.push((v2.0.clone(), v2.1.value.clone())))
                            })
                            .or_else(|| {
                                used_keys.insert(v2.1.source.clone(),
                                                 vec![(v2.0.clone(),
                                                       v2.1.value.clone())]);
                                Some(())
                            })
               })
           });
    }
    result.push(str_line.to_string());
}

fn env_or_prop(key: &str,
               props_first: bool,
               keys: &Option<KeysAndSources>)
               -> Option<(String, ValueAndSource)> {
    match keys {
        &Some(ref k) => {
            let dict = &(k.dictionary);
            let prop = dict.get(key).and_then(|v| Some(v.clone()));
            let env = env::var_os(key)
                          .map(|v2| v2.clone().into_string().ok().unwrap());
            match (prop, props_first) {
                (Some(prop), true) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: prop.value.clone(),
                        source: prop.source.clone(),
                    }))
                }
                (Some(prop), false) => {
                    match env {
                        Some(e) => {
                            println!("[WARNING]: key \"${{{}}}\" from the \
                                      file \"{}\" was overridden by an \
                                      environment variable with the same \
                                      name.",
                                     key.to_string(),
                                     prop.source);
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: prop.value.clone(),
                                source: prop.source.clone(),
                            }))
                        }
                    }
                }
                (None, true) => {
                    match env {
                        Some(e) => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: key.to_string(),
                                source: MISSING.to_string(),
                            }))
                        }
                    }
                }
                (None, false) => {
                    match env {
                        Some(e) => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: e.to_string(),
                                source: ENV.to_string(),
                            }))
                        }
                        None => {
                            Some((key.to_string(),
                                  ValueAndSource {
                                value: key.to_string(),
                                source: MISSING.to_string(),
                            }))
                        }
                    }
                }
            }
        }
        &None => {
            match env::var_os(key)
                      .map(|v| v.into_string().ok())
                      .unwrap_or(None) {
                Some(e) => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: e.to_string(),
                        source: ENV.to_string(),
                    }))
                }
                None => {
                    Some((key.to_string(),
                          ValueAndSource {
                        value: key.to_string(),
                        source: MISSING.to_string(),
                    }))
                }
            }
        }
    }
}

fn process(file: fs::File,
           used_keys: &mut HashMap<String, Vec<(String, String)>>,
           dict: &Option<KeysAndSources>,
           props_first: bool)
           -> Vec<String> {
    let buf_reader = io::BufReader::new(&file);
    let mut result: Vec<String> = vec![];

    for line in buf_reader.lines() {
        replace_var(line.unwrap(), &dict, props_first, used_keys, &mut result);
    }

    result
}

fn extract_keys(file: fs::File) -> HashMap<String, String> {
    let key_regex = regex!(r"^\s*(?P<key>\S*)\s*=\s*(?P<val>.*)");
    let buf_reader = io::BufReader::new(&file);
    let mut keys = HashMap::new();

    for line in buf_reader.lines().enumerate() {
        for cap in key_regex.captures_iter(&*line.1
                                                 .ok()
                                                 .expect("Could not read \
                                                          line")) {
            let key = cap.name("key")
                         .unwrap_or("???");
            let val = cap.name("val")
                         .unwrap_or("???");
            if !keys.contains_key(key) {
                keys.insert(key.to_string(), val.to_string());
            }
        }
    }

    keys
}

#[derive(Debug)]
#[derive(Clone)]
struct ValueAndSource {
    value: String,
    source: String,
}

fn insert_if_not_exist(dict: &mut HashMap<String, ValueAndSource>,
                       keys_from_files: &mut HashMap<String, Vec<String>>,
                       matches: HashMap<String, String>,
                       filename: String) {
    for key_val in matches.iter() {
        let key: String = (*key_val.0).clone();
        let val: String = (*key_val.1).clone();
        match dict.entry(key.clone()) {
            Vacant(e) => {
                e.insert(ValueAndSource {
                    value: val,
                    source: filename.clone(),
                });
                match keys_from_files.entry(filename.clone()) {
                    Vacant(k) => {
                        k.insert(vec![key.clone()]);
                    }
                    Occupied(mut k) => {
                        k.get_mut().push(key.clone());
                    }
                }

                // keys_from_files.insert(filename.clone(), key.clone());
            }
            Occupied(e) => {
                println!("[ERROR]: key ({}) in file ({}) tried to override the \
                          same key from file ({})",
                         key,
                         filename,
                         e.get().source);
                process::exit(1);
            }
        }
    }
}

fn read_keyfiles_to_dict(key_filenames: Vec<String>) -> Option<KeysAndSources> {
    let mut dict: HashMap<String, ValueAndSource> = HashMap::new();
    let mut keys_from_files = HashMap::new();
    for filename in key_filenames {
        fs::File::open(&filename)
            .and_then(|f| Ok(extract_keys(f)))
            .map(|v| {
                insert_if_not_exist(&mut dict,
                                    &mut keys_from_files,
                                    v,
                                    filename);
            });
    }

    match dict.len() {
        0 => None,
        _ => {
            Some(KeysAndSources {
                dictionary: Box::new(dict),
                sources: Box::new(keys_from_files),
            })
        }
    }
}

fn create_file(filename: &String) -> fs::File {
    match fs::File::create(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not create file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

fn open_file(filename: &String) -> fs::File {
    match fs::File::open(filename) {
        Ok(f) => Some(f),
        Err(e) => {
            println_stderr!("[ERROR]: Could not open file: {}\n{}\n",
                            filename,
                            e);
            APP.print_usage_and_panic();
            None
        }
    }
    .unwrap()
}

struct Settings<'a> {
    key_filenames: Vec<String>,
    prop_filename: &'a String,
    result_filename: &'a String,
    props_first: bool,
}

struct KeysAndSources {
    dictionary: Box<HashMap<String, ValueAndSource>>,
    sources: Box<HashMap<String, Vec<String>>>,
}

fn print_result(used_keys: &mut HashMap<String, Vec<(String, String)>>, prop_filename: &String){

    println!("======== RESULTS ========");

    let env_vars = &used_keys.remove(ENV);
    if env_vars.is_some() {
        let vars = env_vars.clone().unwrap();
        println!("# Environment variables:");
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
    }

    for src in used_keys.iter() {
        println!("# {}:", src.0);
        let mut keys_src = src.1.clone();
        keys_src.sort();
        for s in keys_src {
            println!("${{{}}}", s.0);
        }
        println!("");
    }

    let missing_vars = used_keys.get(MISSING);
    if missing_vars.is_some() {
        let vars = missing_vars.unwrap();
        println!("Missing variables found in {}:", prop_filename);
        for v in vars {
            println!("${{{}}}", v.0);
        }
        println!("");
        println_stderr!("ERROR: Must replace all found variables\n\n");
        process::exit(1);
    }

    if env_vars.is_none() && used_keys.len() == 0 && missing_vars.is_none() {
       println!("[No variables to substitute!]\n");
    }

    println!("...DONE!");
}

fn calc_result(settings: Settings) {
    let prop_file = open_file(&settings.prop_filename);
    let mut result_buff = Vec::new();
    let mut used_keys = HashMap::new();
    let keys_and_sources = read_keyfiles_to_dict(settings.key_filenames);

    let processed_buffer = process(prop_file,
                                   &mut used_keys,
                                   &keys_and_sources,
                                   settings.props_first);

    for line in processed_buffer.iter() {
        result_buff.push(line.clone());
    }

    let mut result_file = create_file(settings.result_filename);

    for line in result_buff {
        result_file.write_all(&format!("{}\n", line).as_bytes()).unwrap();
    }
    result_file.flush().unwrap();

    print_result(&mut used_keys, settings.prop_filename);
}

fn get_arg_parser() -> ApplicationOptions {
    ApplicationOptions::new(|| {
        let mut o = OptionsAndFlags::new();
        o.parsing_style(getopts::ParsingStyle::StopAtFirstFree);
        o.opt("k",
              "keys",
              "keyfile(s) with variable substitutions, can occur multiple \
               times",
              "FILE(s)",
              getopts::HasArg::Yes,
              getopts::Occur::Multi)
         .unwrap();
        o.opt("p",
              "props-first",
              "properties takes precedence over environment variables \
               (default: off)",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("?",
              "help",
              "print this help menu",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        o.opt("V",
              "version",
              "prints current version number",
              "",
              getopts::HasArg::No,
              getopts::Occur::Optional)
         .unwrap();
        Ok(o)
    })
}

struct PropAndResultFilenames<'a> {
    prop_filename: &'a String,
    result_filename: &'a String,
}

fn get_prop_and_result_filename<'a>(free_args: &'a Vec<String>)
                                    -> PropAndResultFilenames<'a> {
    match free_args.len() {
        1 => {
            // Replace vars in the provided file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[0],
            }
        }
        2 => {
            // Replace vars into a separate output file
            PropAndResultFilenames {
                prop_filename: &free_args[0],
                result_filename: &free_args[1],
            }
        }
        _ => {
            println_stderr!("Wrong number of file parameters: {}",
                            free_args.len());
            APP.print_usage();
            process::exit(1);
        }
    }
}

fn get_props_first(matches: &Box<getopts::Matches>) -> bool {
    if matches.opt_present("p") {
        true
    } else {
        false
    }

}

fn get_parsed_args() -> Box<getopts::Matches> {
    Box::new(APP.parse().unwrap_or_else(|e| {
        println_stderr!("{}", e);
        process::exit(1);
    }))
}

// Singletons
lazy_static! {
    static ref APP: ApplicationOptions = get_arg_parser();
}

#[allow(dead_code)]
fn main() {
    let matches = get_parsed_args();

    if matches.opt_present("V") {
        println!("proper: v{}", VERSION);
        process::exit(0);
    }

    let prop_and_result_filenames = get_prop_and_result_filename(&matches.free);
    calc_result(Settings {
        key_filenames: matches.opt_strs("k"),
        prop_filename: prop_and_result_filenames.prop_filename,
        result_filename: prop_and_result_filenames.result_filename,
        props_first: get_props_first(&matches),
    });
}

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

    struct TestData {
        key_map: HashMap<String, ValueAndSource>,
        used_keys: HashMap<&'static str, Vec<(String, String)>>,
        result: Vec<String>,
    }

    fn create_test_data(keys: Vec<(&str, &str)>) -> TestData {
        let mut test_data = TestData {
            key_map: HashMap::new(),
            used_keys: HashMap::new(),
            result: Vec::new(),
        };

        for k in keys {
            test_data.key_map.insert(k.0.to_string(),
                                     ValueAndSource {
                                         value: k.1.to_string(),
                                         source: "".to_string(),
                                     });
        }

        test_data
    }

    #[test]
    fn can_sub_single_var() {
        let mut test_data = create_test_data(vec![("val", "world!")]);
        replace_var("Hello ${val}".to_string(),
                    &Some(test_data.key_map),
                    true,
                    &mut test_data.used_keys,
                    &mut test_data.result);
        assert!(test_data.result.len() == 1);
        assert!(test_data.used_keys[super::KEY_FILE][0].0 == "val".to_string());
        assert!(test_data.result[0] == "Hello world!".to_string());
    }
}
<|endoftext|>