<commit_before>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::ptr;
use std::str::from_utf8;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        // If handle is already setup we just return from here
        if self.handle != ptr::null_mut() {
            return Ok(());
        }

        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn detail(&self) -> Option<&cs_detail> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let d: &cs_detail = transmute(self.detail);
            Some(d)
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<commit_msg>Use cs_detail<commit_after>use libc::{c_int, c_uint, c_void, size_t};
use std::fmt::{Debug, Formatter};
use std::ffi::CStr;
use std::mem::transmute;
use std::ptr;
use std::str::from_utf8;
use capstone_m68k::cs_detail;

#[repr(C)]
pub struct Insn {
    pub id: c_uint,
    pub address: u64,
    pub size: u16,
    pub bytes: [u8; 16],
    pub mnemonic: [i8; 32],
    pub op_str: [i8; 160],
    pub detail: *const c_void,
}

#[repr(C)]
pub struct CCapstone1 {
    version: extern "C" fn(major: *mut c_int, minor: *mut c_int) -> c_uint,
    support: extern "C" fn(query: c_int) -> c_int,
    open: extern "C" fn(arch: c_int, mode: c_int, handle: *mut *const c_void) -> c_int,
    close: extern "C" fn(handle: *mut *const c_void) -> c_int,
    option: extern "C" fn(handle: *const c_void, _type: c_int, value: size_t) -> c_int,
    err: extern "C" fn(handle: *const c_void) -> c_int,
    disasm: extern "C" fn(handle: *const c_void,
                          code: *const u8,
                          code_size: size_t,
                          address: u64,
                          count: size_t,
                          insn: &mut *const Insn)
                          -> size_t,
    free: extern "C" fn(insn: *const Insn, count: size_t),
}

#[derive(Clone, Copy, Debug)]
pub enum Arch {
    Arm = 0,
    Arm64,
    MIPS,
    X86,
    PowerPC,
    Sparc,
    SystemZ,
    XCore,
    M68K,
}

bitflags!(
    flags Mode: u32 {
        const MODE_LITTLE_ENDIAN = 0,
        const MODE_ARM = 0,
        const MODE_16 = 1 << 1,
        const MODE_32 = 1 << 2,
        const MODE_64 = 1 << 3,
        const MODE_THUMB = 1 << 4,
        const MODE_MCLASS = 1 << 5,
        const MODE_V8 = 1 << 6,
        const MODE_MICRO = 1 << 4,
        const MODE_MIPS3 = 1 << 5,
        const MODE_MIPS32R6 = 1 << 6,
        const MODE_MIPSGP64 = 1 << 7,
        const MODE_V9 = 1 << 4,
        const CS_MODE_QPX = 1 << 4,
        const CS_MODE_M68K_000 = 1 << 1,
        const CS_MODE_M68K_010 = 1 << 2,
        const CS_MODE_M68K_020 = 1 << 3,
        const CS_MODE_M68K_030 = 1 << 4,
        const CS_MODE_M68K_040 = 1 << 5,
        const CS_MODE_M68K_060 = 1 << 6,
        const MODE_BIG_ENDIAN= 1 << 31,
        const MODE_MIPS32 = 1 << 2,
        const MODE_MIPS64 = 1 << 3,
    }
);

#[derive(Clone, Copy, Debug)]
pub enum Opt {
    Syntax = 1,
    Detail,
    Mode, // OptMem
}

#[repr(i32)]
pub enum Error {
    /// No error: everything was fine
    Ok,
    /// Out-Of-Memory error: cs_open(), cs_disasm(), cs_disasm_iter()
    Mem,
    /// Unsupported architecture: cs_open()
    Arch,
    /// Invalid handle: cs_op_count(), cs_op_index()
    Handle,
    /// Invalid csh argument: cs_close(), cs_errno(), cs_option()
    Csh,
    /// Invalid/unsupported mode: cs_open()
    Mode,
    /// Invalid/unsupported option: cs_option()
    InvOption,
    /// Information is unavailable because detail option is OFF
    Detail,
    /// Dynamic memory management uninitialized (see CS_OPT_MEM)
    MemSetup,
    /// Unsupported version (bindings)
    Version,
    /// Access irrelevant data in "diet" engine
    Diet,
    /// Access irrelevant data for "data" instruction in SKIPDATA mode
    Skipdata,
    /// X86 AT&T syntax is unsupported (opt-out at compile time)
    Att,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Intel,
    /// X86 Intel syntax is unsupported (opt-out at compile time)
    Mask,
}

pub struct Capstone {
    pub api: *mut CCapstone1,
    pub handle: *const c_void,
}

impl Capstone {
    pub fn open(&mut self, arch: Arch, mode: Mode) -> Result<(), Error> {
        // If handle is already setup we just return from here
        if self.handle != ptr::null_mut() {
            return Ok(());
        }

        let mut handle: *const c_void = 0 as *const c_void;
        unsafe {
            match ((*self.api).open)(arch as c_int, mode.bits as c_int, &mut handle) {
                0 => {
                    self.handle = handle;
                    Ok(())
                }
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn set_option(&self, option: Opt, value: usize) -> Result<(), Error> {
        unsafe {
            match ((*self.api).option)(self.handle, option as c_int, value as size_t) {
                0 => Ok(()),
                e => {
                    let err: Error = transmute(e);
                    Err(err)
                }
            }
        }
    }

    pub fn disasm(&self, code: &[u8], addr: u64, count: usize) -> Result<Instructions, Error> {
        let mut ptr: *const Insn = ptr::null();
        let insn_count;
        unsafe {
            insn_count = ((*self.api).disasm)(self.handle,
                                              code.as_ptr(),
                                              code.len() as size_t,
                                              addr,
                                              count as size_t,
                                              &mut ptr) as isize;
        }

        if insn_count == 0 {
            unsafe {
                let num = ((*self.api).err)(self.handle);
                let err: Error = transmute(num);
                return Err(err);
            }
        }

        Ok(Instructions::from_raw_parts(self.api, ptr, insn_count as isize))
    }
}

// Using an actual slice is causing issues with auto deref, instead implement a custom iterator and
// drop trait
pub struct Instructions {
    pub api: *mut CCapstone1,
    ptr: *const Insn,
    len: isize,
}

impl Instructions {
    // This method really shouldn't be public, but it was unclear how to make it visible in lib.rs
    // but not globally visible.
    fn from_raw_parts(api: *mut CCapstone1, ptr: *const Insn, len: isize) -> Instructions {
        Instructions {
            api: api,
            ptr: ptr,
            len: len,
        }
    }

    pub fn len(&self) -> isize {
        self.len
    }

    pub fn iter(&self) -> InstructionIterator {
        InstructionIterator {
            insns: &self,
            cur: 0,
        }
    }
}

impl Drop for Instructions {
    fn drop(&mut self) {
        unsafe {
            ((*self.api).free)(self.ptr, self.len as size_t);
        }
    }
}

pub struct InstructionIterator<'a> {
    insns: &'a Instructions,
    cur: isize,
}

impl<'a> Iterator for InstructionIterator<'a> {
    type Item = Insn;

    fn next(&mut self) -> Option<Insn> {
        if self.cur == self.insns.len {
            None
        } else {
            let obj = unsafe { self.insns.ptr.offset(self.cur) };
            self.cur += 1;
            Some(unsafe { ptr::read(obj) })
        }
    }
}

impl Insn {
    pub fn mnemonic(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.mnemonic.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn op_str(&self) -> Option<&str> {
        let cstr = unsafe { CStr::from_ptr(self.op_str.as_ptr()) };
        from_utf8(cstr.to_bytes()).ok()
    }

    pub fn detail(&self) -> Option<&cs_detail> {
        unsafe {
            if self.detail == ptr::null() {
                return None;
            }

            let d: &cs_detail = transmute(self.detail);
            Some(d)
        }
    }
}

impl Debug for Insn {
    fn fmt(&self, fmt: &mut Formatter) -> Result<(), ::std::fmt::Error> {
        fmt.debug_struct("Insn")
           .field("address", &self.address)
           .field("size", &self.size)
           .field("mnemonic", &self.mnemonic())
           .field("op_str", &self.op_str())
           .finish()
    }
}
<|endoftext|>


<commit_before>#[link(name = "OpenCL",
       version = "0.1",
       uuid = "26bc3ce8-7720-41a7-9280-c522285f2e70")];
#[crate_type = "lib"];
#[feature(macro_rules)];
#[feature(globs)];
#[feature(managed_boxes)];
#[feature(link_args)];

//! OpenCL bindings for Rust.

extern mod std;

#[nolink]
#[link_args = "-framework OpenCL"]
#[cfg(target_os = "macos")]
extern { }

#[link(name = "OpenCL")]
#[cfg(target_os = "linux")]
extern { }

/// Low-level OpenCL bindings. These should primarily be used by the
/// higher level features in this library.
pub mod CL;
pub mod error;
pub mod hl;
pub mod util;
pub mod mem;
pub mod array;
<commit_msg>Add pkgid for rustdoc.<commit_after>#[pkgid = "OpenCL"];
#[link(name = "OpenCL",
       version = "0.1",
       uuid = "26bc3ce8-7720-41a7-9280-c522285f2e70")];
#[crate_type = "lib"];
#[feature(macro_rules)];
#[feature(globs)];
#[feature(managed_boxes)];
#[feature(link_args)];

//! OpenCL bindings for Rust.

extern mod std;

#[nolink]
#[link_args = "-framework OpenCL"]
#[cfg(target_os = "macos")]
extern { }

#[link(name = "OpenCL")]
#[cfg(target_os = "linux")]
extern { }

/// Low-level OpenCL bindings. These should primarily be used by the
/// higher level features in this library.
pub mod CL;
pub mod error;
pub mod hl;
pub mod util;
pub mod mem;
pub mod array;
<|endoftext|>


<commit_before>// Sync available crate categories from `src/categories.toml`.
// Runs when the server is started.

use diesel;
use diesel::prelude::*;
use toml;

use db;
use schema::categories;
use util::errors::{CargoResult, ChainError, internal};

#[derive(Debug)]
struct Category {
    slug: String,
    name: String,
    description: String,
}

impl Category {
    fn from_parent(
        slug: &str,
        name: &str,
        description: &str,
        parent: Option<&Category>,
    ) -> Category {
        match parent {
            Some(parent) => {
                Category {
                    slug: format!("{}::{}", parent.slug, slug),
                    name: format!("{}::{}", parent.name, name),
                    description: description.into(),
                }
            }
            None => {
                Category {
                    slug: slug.into(),
                    name: name.into(),
                    description: description.into(),
                }
            }
        }
    }
}

fn required_string_from_toml<'a>(toml: &'a toml::value::Table, key: &str) -> CargoResult<&'a str> {
    toml.get(key).and_then(toml::Value::as_str).chain_error(|| {
        internal(&format_args!(
            "Expected category TOML attribute '{}' to be a String",
            key
        ))
    })
}

fn optional_string_from_toml<'a>(toml: &'a toml::value::Table, key: &str) -> &'a str {
    toml.get(key).and_then(toml::Value::as_str).unwrap_or("")
}

fn categories_from_toml(
    categories: &toml::value::Table,
    parent: Option<&Category>,
) -> CargoResult<Vec<Category>> {
    let mut result = vec![];

    for (slug, details) in categories {
        let details = details.as_table().chain_error(|| {
            internal(&format_args!("category {} was not a TOML table", slug))
        })?;

        let category = Category::from_parent(
            slug,
            required_string_from_toml(details, "name")?,
            optional_string_from_toml(details, "description"),
            parent,
        );

        if let Some(categories) = details.get("categories") {
            let categories = categories.as_table().chain_error(|| {
                internal(&format_args!(
                    "child categories of {} were not a table",
                    slug
                ))
            })?;

            result.extend(categories_from_toml(categories, Some(&category))?);
        }

        result.push(category)
    }

    Ok(result)
}

#[derive(Insertable)]
#[table_name = "categories"]
struct NewCategory {
    slug: String,
    category: String,
    description: String,
}

pub fn sync(toml_str: &str) -> CargoResult<()> {
    use diesel::pg::upsert::*;
    use diesel::expression::dsl::all;

    let conn = db::connect_now().unwrap();

    let toml: toml::value::Table =
        toml::from_str(toml_str).expect("Could not parse categories toml");

    let categories = categories_from_toml(&toml, None)
        .expect("Could not convert categories from TOML")
        .into_iter()
        .map(|c| {
            NewCategory {
                slug: c.slug.to_lowercase(),
                category: c.name,
                description: c.description,
            }
        })
        .collect::<Vec<_>>();

    let to_insert = categories.on_conflict(
        categories::slug,
        do_update().set((
            categories::category.eq(excluded(categories::category)),
            categories::description.eq(
                excluded(categories::description),
            ),
        )),
    );

    conn.transaction(|| {
        let slugs = diesel::insert(&to_insert)
            .into(categories::table)
            .returning(categories::slug)
            .get_results::<String>(&conn)?;

        let to_delete = categories::table.filter(categories::slug.ne(all(slugs)));
        diesel::delete(to_delete).execute(&conn)?;
        Ok(())
    })
}
<commit_msg>Make connection optionally injectable<commit_after>// Sync available crate categories from `src/categories.toml`.
// Runs when the server is started.

use diesel;
use diesel::prelude::*;
use diesel::pg::PgConnection;
use toml;

use db;
use schema::categories;
use util::errors::{CargoResult, ChainError, internal};

#[derive(Debug)]
struct Category {
    slug: String,
    name: String,
    description: String,
}

impl Category {
    fn from_parent(
        slug: &str,
        name: &str,
        description: &str,
        parent: Option<&Category>,
    ) -> Category {
        match parent {
            Some(parent) => {
                Category {
                    slug: format!("{}::{}", parent.slug, slug),
                    name: format!("{}::{}", parent.name, name),
                    description: description.into(),
                }
            }
            None => {
                Category {
                    slug: slug.into(),
                    name: name.into(),
                    description: description.into(),
                }
            }
        }
    }
}

fn required_string_from_toml<'a>(toml: &'a toml::value::Table, key: &str) -> CargoResult<&'a str> {
    toml.get(key).and_then(toml::Value::as_str).chain_error(|| {
        internal(&format_args!(
            "Expected category TOML attribute '{}' to be a String",
            key
        ))
    })
}

fn optional_string_from_toml<'a>(toml: &'a toml::value::Table, key: &str) -> &'a str {
    toml.get(key).and_then(toml::Value::as_str).unwrap_or("")
}

fn categories_from_toml(
    categories: &toml::value::Table,
    parent: Option<&Category>,
) -> CargoResult<Vec<Category>> {
    let mut result = vec![];

    for (slug, details) in categories {
        let details = details.as_table().chain_error(|| {
            internal(&format_args!("category {} was not a TOML table", slug))
        })?;

        let category = Category::from_parent(
            slug,
            required_string_from_toml(details, "name")?,
            optional_string_from_toml(details, "description"),
            parent,
        );

        if let Some(categories) = details.get("categories") {
            let categories = categories.as_table().chain_error(|| {
                internal(&format_args!(
                    "child categories of {} were not a table",
                    slug
                ))
            })?;

            result.extend(categories_from_toml(categories, Some(&category))?);
        }

        result.push(category)
    }

    Ok(result)
}

#[derive(Insertable)]
#[table_name = "categories"]
struct NewCategory {
    slug: String,
    category: String,
    description: String,
}

pub fn sync(toml_str: &str) -> CargoResult<()> {
    let conn = db::connect_now().unwrap();
    sync_with_connection(toml_str, &conn)
}

pub fn sync_with_connection(toml_str: &str, conn: &PgConnection)  -> CargoResult<()> {
    use diesel::pg::upsert::*;
    use diesel::expression::dsl::all;

    let toml: toml::value::Table =
        toml::from_str(toml_str).expect("Could not parse categories toml");

    let categories = categories_from_toml(&toml, None)
        .expect("Could not convert categories from TOML")
        .into_iter()
        .map(|c| {
            NewCategory {
                slug: c.slug.to_lowercase(),
                category: c.name,
                description: c.description,
            }
        })
        .collect::<Vec<_>>();

    let to_insert = categories.on_conflict(
        categories::slug,
        do_update().set((
            categories::category.eq(excluded(categories::category)),
            categories::description.eq(
                excluded(categories::description),
            ),
        )),
    );

    conn.transaction(|| {
        let slugs = diesel::insert(&to_insert)
            .into(categories::table)
            .returning(categories::slug)
            .get_results::<String>(&*conn)?;

        let to_delete = categories::table.filter(categories::slug.ne(all(slugs)));
        diesel::delete(to_delete).execute(&*conn)?;
        Ok(())
    })
}
<|endoftext|>


<commit_before>#![allow(unused_imports, unused_variables, unused_attributes, dead_code)]

use clap::error::{ContextKind, ContextValue, ErrorKind};
use clap::Error;
use clap::{arg, Arg, ArgMatches, Command};

use std::env;
use std::fmt::Debug;
use std::ops::Range;
use std::path::PathBuf;
use std::str::FromStr;

use crate::cfg::spec::{Nargs, Otto, Param, Spec, Task, Value};

#[macro_use]
use super::macros;
use super::error;

fn print_type_of<T: ?Sized>(t: &T)
where
    T: Debug,
{
    println!("type={} value={:#?}", std::any::type_name::<T>(), t);
}

fn extract(item: (ContextKind, &ContextValue)) -> Option<&ContextValue> {
    let (k, v) = item;
    if k == ContextKind::InvalidArg {
        return Some(v);
    }
    None
}

pub trait GetKnownMatches {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error>;
    fn get_known_matches_from(
        &self,
        args: &mut Vec<String>,
    ) -> Result<(ArgMatches, Vec<String>), Error>;
}

impl<'a> GetKnownMatches for Command<'a> {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut args: Vec<String> = env::args().collect();
        self.get_known_matches_from(&mut args)
    }
    fn get_known_matches_from(
        &self,
        args: &mut Vec<String>,
    ) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut rem: Vec<String> = vec![];
        loop {
            match self.clone().try_get_matches_from(&*args) {
                Ok(matches) => {
                    return Ok((matches, rem));
                }
                Err(error) => match error.kind() {
                    ErrorKind::UnknownArgument => {
                        let items = error.context().find_map(extract);
                        match items {
                            Some(x) => match x {
                                ContextValue::String(s) => {
                                    rem.push(s.to_owned());
                                    args.retain(|a| a != s);
                                }
                                _ => {
                                    return Err(error);
                                }
                            },
                            None => {
                                return Err(error);
                            }
                        }
                    }
                    _ => {
                        return Err(error);
                    }
                },
            }
        }
    }
}

#[derive(Debug, Default, PartialEq, Clone)]
struct PartitionedArgs {
    args: Vec<String>,
    partitions: Vec<Range<usize>>,
}
impl PartitionedArgs {
    fn new(tasknames: &[&str]) -> Self {
        let args: Vec<String> = env::args().collect();
        let mut beg = 0;
        let mut partitions = vec![];
        for (i, arg) in args.iter().skip(1).enumerate() {
            if tasknames.iter().any(|t| t == arg) {
                let end = i + 1;
                partitions.push(Range::<usize> { start: beg, end });
                beg = end;
            }
        }
        partitions.push(Range::<usize> {
            start: beg,
            end: args.len(),
        });
        Self { args, partitions }
    }
    fn partitions(&self) -> Vec<&[String]> {
        self.partitions
            .iter()
            .map(|p| &self.args[p.clone()])
            .collect()
    }
    fn partition(&self, index: usize) -> Option<&[String]> {
        if index < self.len() {
            return Some(&self.args[self.partitions[index].clone()]);
        }
        None
    }
    fn len(&self) -> usize {
        self.partitions.len()
    }
}

fn otto_seed() -> Command<'static> {
    Command::new("otto")
        .disable_help_flag(true)
        .disable_version_flag(true)
        .arg(
            Arg::new("ottofile")
                .takes_value(true)
                .short('o')
                .long("ottofile")
                .help("path to ottofile"),
        )
}

#[derive(Debug, PartialEq)]
pub struct Parser<'a> {
    spec: &'a Spec,
}

impl<'a> Parser<'a> {
    pub fn new(spec: &'a Spec) -> Self {
        Self { spec }
    }
    fn task_names(&self) -> Vec<&str> {
        self.spec.otto.tasks.keys().map(AsRef::as_ref).collect()
    }
    pub fn divine_ottofile() -> PathBuf {
        let ottofile = match otto_seed().get_known_matches() {
            Ok((matches, _)) => {
                let result = matches.value_of("ottofile");
                println!("result={:?}", result);
                result.unwrap_or("./otto.yml").to_string()
            }
            Err(error) => {
                println!("divine: error={}", error);
                "./otto.yml".to_string()
            }
        };
        PathBuf::from_str(&ottofile).unwrap()
    }

    pub fn parse(&self) -> Vec<ArgMatches> {
        println!("task_names={:#?}", self.task_names());
        let pa = PartitionedArgs::new(&self.task_names());
        println!("pa={:#?}", pa);
        /*
        print_type_of(&args);
        println!("otto_args={:#?}", otto_args);
        print_type_of(&otto_args);
        let matches = self.otto_parser().get_matches_from(otto_args);
        print_type_of(&matches);
        let ottofile = matches.value_of("ottofile").unwrap_or("./");
        print_type_of(&ottofile);
        let mut pathbuf = PathBuf::new();
        pathbuf.push(ottofile);
        print_type_of(&pathbuf);
        let exists = pathbuf.exists();
        print_type_of(&exists);
        */
        vec![]
    }
    /*
    fn tasks_to_commands(&self) -> Vec<Command> {
        fn param_to_arg(param: &Param) -> Arg {
            println!("param={:#?}", param);
            let mut arg = Arg::new(&*param.name);
            if let Some(help) = &param.help {
                println!("help={:?}", help);
                arg = arg.help(Some(&help[..]));
            }
            arg
        }
        fn task_to_command(task: &Task) -> Command {
            let args: Vec<Arg> = task.params.values().map(param_to_arg).collect();
            Command::new(task.name.to_owned()).args(args)
        }
        self.tasks().iter().map(|t| task_to_command(t)).collect()
    }
    */
}
<commit_msg>collapsed nested match branches<commit_after>#![allow(unused_imports, unused_variables, unused_attributes, dead_code)]

use clap::error::{ContextKind, ContextValue, ErrorKind};
use clap::Error;
use clap::{arg, Arg, ArgMatches, Command};

use std::env;
use std::fmt::Debug;
use std::ops::Range;
use std::path::PathBuf;
use std::str::FromStr;

use crate::cfg::spec::{Nargs, Otto, Param, Spec, Task, Value};

#[macro_use]
use super::macros;
use super::error;

fn print_type_of<T: ?Sized>(t: &T)
where
    T: Debug,
{
    println!("type={} value={:#?}", std::any::type_name::<T>(), t);
}

fn extract(item: (ContextKind, &ContextValue)) -> Option<&ContextValue> {
    let (k, v) = item;
    if k == ContextKind::InvalidArg {
        return Some(v);
    }
    None
}

pub trait GetKnownMatches {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error>;
    fn get_known_matches_from(
        &self,
        args: &mut Vec<String>,
    ) -> Result<(ArgMatches, Vec<String>), Error>;
}

impl<'a> GetKnownMatches for Command<'a> {
    fn get_known_matches(&self) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut args: Vec<String> = env::args().collect();
        self.get_known_matches_from(&mut args)
    }
    fn get_known_matches_from(
        &self,
        args: &mut Vec<String>,
    ) -> Result<(ArgMatches, Vec<String>), Error> {
        let mut rem: Vec<String> = vec![];
        loop {
            match self.clone().try_get_matches_from(&*args) {
                Ok(matches) => {
                    return Ok((matches, rem));
                }
                Err(error) => match error.kind() {
                    ErrorKind::UnknownArgument => {
                        let items = error.context().find_map(extract);
                        match items {
                            Some(ContextValue::String(s)) => {
                                rem.push(s.to_owned());
                                args.retain(|a| a != s);
                            }
                            Some(&_) => {
                                return Err(error);
                            }
                            None => {
                                return Err(error);
                            }
                        }
                    }
                    _ => {
                        return Err(error);
                    }
                },
            }
        }
    }
}

#[derive(Debug, Default, PartialEq, Clone)]
struct PartitionedArgs {
    args: Vec<String>,
    partitions: Vec<Range<usize>>,
}
impl PartitionedArgs {
    fn new(tasknames: &[&str]) -> Self {
        let args: Vec<String> = env::args().collect();
        let mut beg = 0;
        let mut partitions = vec![];
        for (i, arg) in args.iter().skip(1).enumerate() {
            if tasknames.iter().any(|t| t == arg) {
                let end = i + 1;
                partitions.push(Range::<usize> { start: beg, end });
                beg = end;
            }
        }
        partitions.push(Range::<usize> {
            start: beg,
            end: args.len(),
        });
        Self { args, partitions }
    }
    fn partitions(&self) -> Vec<&[String]> {
        self.partitions
            .iter()
            .map(|p| &self.args[p.clone()])
            .collect()
    }
    fn partition(&self, index: usize) -> Option<&[String]> {
        if index < self.len() {
            return Some(&self.args[self.partitions[index].clone()]);
        }
        None
    }
    fn len(&self) -> usize {
        self.partitions.len()
    }
}

fn otto_seed() -> Command<'static> {
    Command::new("otto")
        .disable_help_flag(true)
        .disable_version_flag(true)
        .arg(
            Arg::new("ottofile")
                .takes_value(true)
                .short('o')
                .long("ottofile")
                .help("path to ottofile"),
        )
}

#[derive(Debug, PartialEq)]
pub struct Parser<'a> {
    spec: &'a Spec,
}

impl<'a> Parser<'a> {
    pub fn new(spec: &'a Spec) -> Self {
        Self { spec }
    }
    fn task_names(&self) -> Vec<&str> {
        self.spec.otto.tasks.keys().map(AsRef::as_ref).collect()
    }
    pub fn divine_ottofile() -> PathBuf {
        let ottofile = match otto_seed().get_known_matches() {
            Ok((matches, _)) => {
                let result = matches.value_of("ottofile");
                println!("result={:?}", result);
                result.unwrap_or("./otto.yml").to_string()
            }
            Err(error) => {
                println!("divine: error={}", error);
                "./otto.yml".to_string()
            }
        };
        PathBuf::from_str(&ottofile).unwrap()
    }

    pub fn parse(&self) -> Vec<ArgMatches> {
        println!("task_names={:#?}", self.task_names());
        let pa = PartitionedArgs::new(&self.task_names());
        println!("pa={:#?}", pa);
        /*
        print_type_of(&args);
        println!("otto_args={:#?}", otto_args);
        print_type_of(&otto_args);
        let matches = self.otto_parser().get_matches_from(otto_args);
        print_type_of(&matches);
        let ottofile = matches.value_of("ottofile").unwrap_or("./");
        print_type_of(&ottofile);
        let mut pathbuf = PathBuf::new();
        pathbuf.push(ottofile);
        print_type_of(&pathbuf);
        let exists = pathbuf.exists();
        print_type_of(&exists);
        */
        vec![]
    }
    /*
    fn tasks_to_commands(&self) -> Vec<Command> {
        fn param_to_arg(param: &Param) -> Arg {
            println!("param={:#?}", param);
            let mut arg = Arg::new(&*param.name);
            if let Some(help) = &param.help {
                println!("help={:?}", help);
                arg = arg.help(Some(&help[..]));
            }
            arg
        }
        fn task_to_command(task: &Task) -> Command {
            let args: Vec<Arg> = task.params.values().map(param_to_arg).collect();
            Command::new(task.name.to_owned()).args(args)
        }
        self.tasks().iter().map(|t| task_to_command(t)).collect()
    }
    */
}
<|endoftext|>


<commit_before>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

// #[no_mangle]
// pub extern "C" fn some_new_fn() -> c_int {
//     println!("some_new_fn");
//     65 as c_int
// }

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    // println!("start");
    // 88 as c_int

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    // Create and register a way to kill this client
    let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    let kill_tx = k_tx.clone();
    let mut k_tx_ptr = Box::new(k_tx);
    unsafe {
        register_stop_tx(&mut *k_tx_ptr);
    }

    // Writer thread's channel
    let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    let mut w_tx_ptr = Box::new(w_tx);
    unsafe {
        register_writer_tx(&mut *w_tx_ptr);
    }

    println!("Attempting connect to: {}", host_address);

    let result = TcpStream::connect(host_address);
    if result.is_err() {
        println!("Error connecting to {} - {}", host_address, result.unwrap_err());
        return -1 as c_int;
    }
    println!("Connected");
    on_connect_handler();

    let stream = result.unwrap();
    let client = Bstream::new(stream);

    let r_client = client.clone();
    let r_kill_tx = kill_tx.clone();

    let w_client = client.clone();
    let w_kill_tx = kill_tx.clone();

    // Start the reader thread
    thread::Builder::new()
        .name("ReaderThread".to_string())
        .spawn(move||{
            reader_thread(r_client, handler, r_kill_tx)
        }).unwrap();

    // Start the writer thread
    thread::Builder::new()
        .name("WriterThread".to_string())
        .spawn(move||{
            writer_thread(w_rx, w_client, w_kill_tx)
        }).unwrap();

    // Wait for the kill signal
    match kill_rx.recv() {
        Ok(_) => { }
        Err(e) => {
            println!("Error on kill channel: {}", e);
            return -1 as c_int;
        }
    };
    on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

// /// Connects to the provided address, (eg "123.123.123.123:3000") and registers
// /// the on data received handler
// #[no_mangle]
// pub extern "C" fn connect(address: *const c_char,
//     handler: extern fn(*const c_char, c_int),
//     on_connect_handler: extern fn(),
//     on_disconnect_handler: extern fn()) -> c_int {
//
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//
//
//     78 as c_int
//
//
//     let mut r_address;
//     unsafe {
//         r_address = CStr::from_ptr(address);
//     }
//     let s_address = r_address.to_bytes();
//     let host_address = match str::from_utf8(s_address) {
//         Ok(safe_str) => safe_str,
//         Err(_) => {
//             println!("Invalid host address");
//             return -1 as c_int;
//         }
//     };
//
//     // Create and register a way to kill this client
//     let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
//     let kill_tx = k_tx.clone();
//     let mut k_tx_ptr = Box::new(k_tx);
//     unsafe {
//         register_stop_tx(&mut *k_tx_ptr);
//     }
//
//     // Writer thread's channel
//     let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
//     let mut w_tx_ptr = Box::new(w_tx);
//     unsafe {
//         register_writer_tx(&mut *w_tx_ptr);
//     }
//
//     println!("Attempting connect to: {}", host_address);
//
//     let result = TcpStream::connect(host_address);
//     if result.is_err() {
//         println!("Error connecting to {} - {}", host_address, result.unwrap_err());
//         return -1 as c_int;
//     }
//     println!("Connected");
//     on_connect_handler();
//
//     let stream = result.unwrap();
//     let client = Bstream::new(stream);
//
//     let r_client = client.clone();
//     let r_kill_tx = kill_tx.clone();
//
//     let w_client = client.clone();
//     let w_kill_tx = kill_tx.clone();
//
//     // Start the reader thread
//     thread::Builder::new()
//         .name("ReaderThread".to_string())
//         .spawn(move||{
//             reader_thread(r_client, handler, r_kill_tx)
//         }).unwrap();
//
//     // Start the writer thread
//     thread::Builder::new()
//         .name("WriterThread".to_string())
//         .spawn(move||{
//             writer_thread(w_rx, w_client, w_kill_tx)
//         }).unwrap();
//
//     // Wait for the kill signal
//     match kill_rx.recv() {
//         Ok(_) => { }
//         Err(e) => {
//             println!("Error on kill channel: {}", e);
//             return -1 as c_int;
//         }
//     };
//     on_disconnect_handler();
//
//     // Exit out in standard C fashion
//     0 as c_int
// }

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<commit_msg>Debugging<commit_after>// Copyright 2015 Nathan Sizemore <nathanrsizemore@gmail.com>
//
// This Source Code Form is subject to the
// terms of the Mozilla Public License, v.
// 2.0. If a copy of the MPL was not
// distributed with this file, You can
// obtain one at
// http://mozilla.org/MPL/2.0/.
//
// This Source Code Form is "Incompatible
// With Secondary Licenses", as defined by
// the Mozilla Public License, v. 2.0.

use std::{str, ptr};
use std::ffi::{CStr, CString};
use std::thread;
use std::net::TcpStream;
use std::sync::mpsc::{channel, Sender, Receiver};

use super::libc::{c_int, c_char};
use super::simple_stream::bstream::Bstream;

extern "C" {
    fn register_writer_tx(tx: *mut Sender<Vec<u8>>);
    fn register_stop_tx(tx: *mut Sender<()>);
}

// #[no_mangle]
// pub extern "C" fn some_new_fn() -> c_int {
//     println!("some_new_fn");
//     65 as c_int
// }

#[no_mangle]
pub extern "C" fn start(address: *const c_char,
    handler: extern fn(*const c_char, c_int),
    on_connect_handler: extern fn(),
    on_disconnect_handler: extern fn()) -> c_int {

    println!("Rust - start()");

    // println!("start");
    // 88 as c_int

    let mut r_address;
    unsafe {
        r_address = CStr::from_ptr(address);
    }
    let s_address = r_address.to_bytes();
    let host_address = match str::from_utf8(s_address) {
        Ok(safe_str) => safe_str,
        Err(_) => {
            println!("Invalid host address");
            return -1 as c_int;
        }
    };

    println!("Rust - address: {}", host_address);

    // // Create and register a way to kill this client
    // let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
    // let kill_tx = k_tx.clone();
    // let mut k_tx_ptr = Box::new(k_tx);
    // unsafe {
    //     register_stop_tx(&mut *k_tx_ptr);
    // }
    //
    // // Writer thread's channel
    // let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
    // let mut w_tx_ptr = Box::new(w_tx);
    // unsafe {
    //     register_writer_tx(&mut *w_tx_ptr);
    // }
    //
    // println!("Attempting connect to: {}", host_address);
    //
    // let result = TcpStream::connect(host_address);
    // if result.is_err() {
    //     println!("Error connecting to {} - {}", host_address, result.unwrap_err());
    //     return -1 as c_int;
    // }
    // println!("Connected");
    // on_connect_handler();
    //
    // let stream = result.unwrap();
    // let client = Bstream::new(stream);
    //
    // let r_client = client.clone();
    // let r_kill_tx = kill_tx.clone();
    //
    // let w_client = client.clone();
    // let w_kill_tx = kill_tx.clone();
    //
    // // Start the reader thread
    // thread::Builder::new()
    //     .name("ReaderThread".to_string())
    //     .spawn(move||{
    //         reader_thread(r_client, handler, r_kill_tx)
    //     }).unwrap();
    //
    // // Start the writer thread
    // thread::Builder::new()
    //     .name("WriterThread".to_string())
    //     .spawn(move||{
    //         writer_thread(w_rx, w_client, w_kill_tx)
    //     }).unwrap();
    //
    // // Wait for the kill signal
    // match kill_rx.recv() {
    //     Ok(_) => { }
    //     Err(e) => {
    //         println!("Error on kill channel: {}", e);
    //         return -1 as c_int;
    //     }
    // };
    // on_disconnect_handler();

    // Exit out in standard C fashion
    0 as c_int
}

// /// Connects to the provided address, (eg "123.123.123.123:3000") and registers
// /// the on data received handler
// #[no_mangle]
// pub extern "C" fn connect(address: *const c_char,
//     handler: extern fn(*const c_char, c_int),
//     on_connect_handler: extern fn(),
//     on_disconnect_handler: extern fn()) -> c_int {
//
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//     println!("Rust - connect");
//
//
//     78 as c_int
//
//
//     let mut r_address;
//     unsafe {
//         r_address = CStr::from_ptr(address);
//     }
//     let s_address = r_address.to_bytes();
//     let host_address = match str::from_utf8(s_address) {
//         Ok(safe_str) => safe_str,
//         Err(_) => {
//             println!("Invalid host address");
//             return -1 as c_int;
//         }
//     };
//
//     // Create and register a way to kill this client
//     let (k_tx, kill_rx): (Sender<()>, Receiver<()>) = channel();
//     let kill_tx = k_tx.clone();
//     let mut k_tx_ptr = Box::new(k_tx);
//     unsafe {
//         register_stop_tx(&mut *k_tx_ptr);
//     }
//
//     // Writer thread's channel
//     let (w_tx, w_rx): (Sender<Vec<u8>>, Receiver<Vec<u8>>) = channel();
//     let mut w_tx_ptr = Box::new(w_tx);
//     unsafe {
//         register_writer_tx(&mut *w_tx_ptr);
//     }
//
//     println!("Attempting connect to: {}", host_address);
//
//     let result = TcpStream::connect(host_address);
//     if result.is_err() {
//         println!("Error connecting to {} - {}", host_address, result.unwrap_err());
//         return -1 as c_int;
//     }
//     println!("Connected");
//     on_connect_handler();
//
//     let stream = result.unwrap();
//     let client = Bstream::new(stream);
//
//     let r_client = client.clone();
//     let r_kill_tx = kill_tx.clone();
//
//     let w_client = client.clone();
//     let w_kill_tx = kill_tx.clone();
//
//     // Start the reader thread
//     thread::Builder::new()
//         .name("ReaderThread".to_string())
//         .spawn(move||{
//             reader_thread(r_client, handler, r_kill_tx)
//         }).unwrap();
//
//     // Start the writer thread
//     thread::Builder::new()
//         .name("WriterThread".to_string())
//         .spawn(move||{
//             writer_thread(w_rx, w_client, w_kill_tx)
//         }).unwrap();
//
//     // Wait for the kill signal
//     match kill_rx.recv() {
//         Ok(_) => { }
//         Err(e) => {
//             println!("Error on kill channel: {}", e);
//             return -1 as c_int;
//         }
//     };
//     on_disconnect_handler();
//
//     // Exit out in standard C fashion
//     0 as c_int
// }

/// Writes the complete contents of buffer to the server
/// Returns -1 on error
#[no_mangle]
pub extern "C" fn send_to_writer(w_tx: *mut Sender<Vec<u8>>,
                                 buffer: *const c_char,
                                 count: c_int,
                                 k_tx: *mut Sender<()>) -> c_int {
    if count < 1 {
        println!("Error - count must be greater than zero");
        return -1 as c_int;
    }

    let num_elts = count as usize;
    let mut n_buffer = Vec::<u8>::with_capacity(num_elts);
    for x in 0..num_elts as isize {
        unsafe {
            n_buffer.push(ptr::read(buffer.offset(x)) as u8);
        }
    }

    unsafe {
        match (*w_tx).send(n_buffer) {
            Ok(_) => { }
            Err(e) => {
                println!("Error sending buffer: {}", e);
                let _ = (*k_tx).send(());
                return -1 as c_int;
            }
        };
    }

    0 as c_int
}

/// Forever listens to incoming data and when a complete message is received,
/// the passed callback is hit
fn reader_thread(client: Bstream,
                 event_handler: extern fn(*const c_char, c_int),
                 kill_tx: Sender<()>) {

    let mut reader = client.clone();
    loop {
        match reader.read() {
            Ok(buffer) => {
                // Launch the handler in a new thread
                thread::Builder::new()
                    .name("Reader-Worker".to_string())
                    .spawn(move||{
                        let slice = &buffer[..];
                        let c_buffer = CString::new(slice).unwrap();
                        event_handler(c_buffer.as_ptr(), buffer.len() as c_int);
                    }).unwrap();
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Reader thread finished");
    let _ = kill_tx.send(());
}

/// Forever listens to Receiver<Vec<u8>> waiting on messages to come in
/// Once available, blocks until the entire message has been written
fn writer_thread(rx: Receiver<Vec<u8>>, client: Bstream, kill_tx: Sender<()>) {
    let mut writer = client.clone();
    loop {
        match rx.recv() {
            Ok(ref mut buffer) => {
                match writer.write(buffer) {
                    Ok(_) => { }
                    Err(e) => {
                        println!("Error: {}", e);
                        break;
                    }
                };
            }
            Err(e) => {
                println!("Error: {}", e);
                break;
            }
        };
    }
    println!("Writer thread finished");
    let _ = kill_tx.send(());
}
<|endoftext|>


<commit_before>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use std::thread;

#[derive(Debug)]
pub enum Task {
    HandleNetworkEvent(network::Event),
    ScheduleMessageDelivery(Address, TextMessage),
    Shutdown
}

#[derive(Debug)]
pub enum ScheduledTask {
    DeliverMessage(Address, TextMessage),
}

#[derive(Clone, Debug)]
pub enum Event {
    ReceivedTextMessage(TextMessage),
    SentTextMessage(TextMessage),
    ReceivedMessageAcknowledgement(MessageAcknowledgement),
    Shutdown
}

pub type TaskSender = mio::Sender<Task>;
pub type Events = mpsc::Receiver<Event>;

pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Client {
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new(),
            event_listeners: Vec::new()
        }
    }

    pub fn run(mut self, mut network: network::Network) -> TaskSender {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        info!("Running client at {}", self.address);
        thread::spawn(move || event_loop.run(&mut self).unwrap());
        notify_channel
    }

    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope;

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if recipient == self.address {
                            if self.received.insert(text_message.id) {
                                let ack = MessageAcknowledgement::new(text_message.id);
                                let sender = text_message.sender;
                                let event = Event::ReceivedTextMessage(text_message);
                                self.broadcast_event(event);
                                self.deliver_acknowledgement(sender, ack, event_loop);
                            }
                        } else {
                            if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                self.acknowledgements.insert(text_message.id, ack);
                            } else {
                                self.schedule_message_delivery(recipient, text_message, event_loop);
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        debug!("ack {}", ack.message_id);
                        self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            if recipient == self.address {
                                self.broadcast_event(Event::ReceivedMessageAcknowledgement(ack));
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
            network::Event::Shutdown => {
                event_loop.shutdown();
                self.broadcast_event(Event::Shutdown);
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message.clone()), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
        self.broadcast_event(Event::SentTextMessage(text_message));
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }

    fn broadcast_event(&self, event: Event) {
        for listener in self.event_listeners.iter() {
            listener.send(event.clone()).expect("Could not broadcast event");
        }
    }

    fn shutdown(&self, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            commands.send(network::OneshotTask::Shutdown).unwrap();
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop),
            Task::Shutdown => self.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<commit_msg>Add documentation to Client<commit_after>pub mod messages;

use address::Address;
use mio;
use network;
use self::messages::{Message, TextMessage, MessageAcknowledgement, Envelope};
use std::collections::{HashMap, HashSet};
use std::sync::mpsc;
use std::thread;

/// A command for the Client to execute immediately.
#[derive(Debug)]
pub enum Task {

    /// Handle events emitted by the `Network`, e.g. handling packets that we receive.
    HandleNetworkEvent(network::Event),

    /// Schedules a message to be delivered.
    ScheduleMessageDelivery(Address, TextMessage),

    /// Shuts down the `Client`. When it has completed the shutdown procedure, it will emit an
    /// `Event::Shutdown`.
    Shutdown
}

/// A task to be performed some time in the future
#[derive(Debug)]
pub enum ScheduledTask {

    /// Deliver a message to an address. This can be a message we are sending to someone else, or
    /// just a message we're relaying.
    DeliverMessage(Address, TextMessage),
}

/// Events emitted to any listeners registered with `register_event_listener`. They represent
/// various client-level events.
#[derive(Clone, Debug)]
pub enum Event {
    /// We've received a message that was addressed to us
    ReceivedTextMessage(TextMessage),

    /// We've sent or relayed a message
    SentTextMessage(TextMessage),

    /// We've received an acknowledgement for a message we sent
    ReceivedMessageAcknowledgement(MessageAcknowledgement),

    /// The client has shut down
    ///
    /// TODO: It might be useful for `Shutdown` to contain the serialized state of the entire
    /// `Client`, `Network`, `RoutingTable`, `Bucket`s and `Nodes` so that a user may store it and
    /// later re-initialize a `Client` with this state in order to prevent re-bootstrapping from
    /// scratch.
    Shutdown
}

/// A sender for issuing commands to the `Client`. Once a client is `run`, it is consumed and
/// methods cannot be called on it. A `TaskSender` as the asynchronous interface for controlling a
/// running `Client`.
pub type TaskSender = mio::Sender<Task>;

/// A receiver for receiving events from a running `Client`. Similar in purpose to `TaskSender`. A
/// running `Client` is consumed and cannot be queried via method calls. You must instead subscribe
/// to events it emits
pub type Events = mpsc::Receiver<Event>;

/// A `Client` handles receiving, processing, relaying, etc. of messages in the communication
/// network. It internalizes all the complex logic that is specific to messaging, and exposes a few
/// commands view a `TaskSender` and events via `Events`.
pub struct Client {
    address: Address,
    network_commands: Option<network::TaskSender>,
    received: HashSet<Address>,
    pending_deliveries: HashMap<Address, mio::Timeout>,
    delivered: HashMap<Address, usize>,
    acknowledgements: HashMap<Address, MessageAcknowledgement>,
    event_listeners: Vec<mpsc::Sender<Event>>
}

impl Client {
    /// Creates a new `Client`. `address` is the address of this client, i.e. where other clients
    /// should send messages intended for this client.
    pub fn new(address: Address) -> Client {
        Client {
            address: address,
            network_commands: None,
            received: HashSet::new(),
            pending_deliveries: HashMap::new(),
            delivered: HashMap::new(),
            acknowledgements: HashMap::new(),
            event_listeners: Vec::new()
        }
    }

    /// Starts a `Client` in its own thread and returns its task sender. This method consumes the
    /// `Client`, so all event listeners must be registered first.
    pub fn run(mut self, mut network: network::Network) -> TaskSender {
        let mut event_loop = mio::EventLoop::new().unwrap();
        let (event_sender, event_receiver) = mpsc::channel();
        network.register_event_listener(event_sender);
        let notify_channel = event_loop.channel();

        thread::spawn(move|| {
            for event in event_receiver.iter() {
                notify_channel
                    .send(Task::HandleNetworkEvent(event))
                    .unwrap_or_else(|err| info!("Couldn't handle network event: {:?}", err));
            }
        });

        self.network_commands = Some(network.run());

        let notify_channel = event_loop.channel();
        info!("Running client at {}", self.address);
        thread::spawn(move || event_loop.run(&mut self).unwrap());
        notify_channel
    }

    /// Registers an event listener that should be sent every `Event` the client emits.
    pub fn register_event_listener(&mut self, event_listener: mpsc::Sender<Event>) {
        self.event_listeners.push(event_listener);
    }

    fn handle_networking_event(&mut self, event: network::Event, event_loop: &mut mio::EventLoop<Client>) {
        match event {
            network::Event::ReceivedPacket(sender, data) => {
                let envelope = messages::decode(data);
                let Envelope { recipient, .. } = envelope;

                match envelope.message {
                    Message::TextMessage(text_message) => {
                        if recipient == self.address {
                            if self.received.insert(text_message.id) {
                                let ack = MessageAcknowledgement::new(text_message.id);
                                let sender = text_message.sender;
                                let event = Event::ReceivedTextMessage(text_message);
                                self.broadcast_event(event);
                                self.deliver_acknowledgement(sender, ack, event_loop);
                            }
                        } else {
                            if let Some(ack) = self.acknowledgements.remove(&text_message.id) {
                                self.deliver_acknowledgement(sender, ack.clone(), event_loop);
                                self.acknowledgements.insert(text_message.id, ack);
                            } else {
                                self.schedule_message_delivery(recipient, text_message, event_loop);
                            }
                        }
                    }
                    Message::MessageAcknowledgement(ack) => {
                        debug!("ack {}", ack.message_id);
                        self.pending_deliveries.remove(&ack.message_id).map(|p| event_loop.clear_timeout(p));

                        if let None = self.acknowledgements.insert(ack.message_id, ack.clone()) {
                            if recipient == self.address {
                                self.broadcast_event(Event::ReceivedMessageAcknowledgement(ack));
                            } else {
                                self.deliver_acknowledgement(recipient, ack, event_loop);
                            }
                        }
                    }
                }
            }
            network::Event::Shutdown => {
                event_loop.shutdown();
                self.broadcast_event(Event::Shutdown);
            }
        }
    }

    fn schedule_message_delivery(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let message_id = text_message.id;
        if !self.pending_deliveries.contains_key(&message_id) {
            let delivered = self.delivered.entry(message_id).or_insert(0);
            let delay = (2u64.pow(*delivered as u32) - 1) * 1000;
            debug!("Deliver {} with delay {:?}", message_id, delay);
            let timeout = event_loop.timeout_ms(ScheduledTask::DeliverMessage(recipient, text_message.clone()), delay).unwrap();
            self.pending_deliveries.insert(message_id, timeout);
            *delivered += 1;
        }
        self.broadcast_event(Event::SentTextMessage(text_message));
    }

    fn deliver_acknowledgement(&mut self, recipient: Address, acknowledgement: MessageAcknowledgement, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            let envelope = acknowledgement.envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode())).unwrap();
        }
    }

    fn deliver_message(&mut self, recipient: Address, text_message: TextMessage, event_loop: &mut mio::EventLoop<Client>) {
        let delivered = self.network_commands.as_ref().map(|commands| {
            let envelope = text_message.clone().envelope(recipient);
            commands.send(network::OneshotTask::SendPacket(recipient, envelope.encode()))
        }).unwrap();

        if let Ok(_) = delivered {
            self.pending_deliveries.remove(&text_message.id);
            self.schedule_message_delivery(recipient, text_message, event_loop);
        }
    }

    fn broadcast_event(&self, event: Event) {
        for listener in self.event_listeners.iter() {
            listener.send(event.clone()).expect("Could not broadcast event");
        }
    }

    fn shutdown(&self, _event_loop: &mut mio::EventLoop<Client>) {
        if let Some(ref commands) = self.network_commands {
            commands.send(network::OneshotTask::Shutdown).unwrap();
        }
    }
}

impl mio::Handler for Client {
    type Timeout = ScheduledTask;
    type Message = Task;

    fn notify(&mut self, event_loop: &mut mio::EventLoop<Client>, task: Task) {
        match task {
            Task::HandleNetworkEvent(event) => self.handle_networking_event(event, event_loop),
            Task::ScheduleMessageDelivery(recipient, message) => self.schedule_message_delivery(recipient, message, event_loop),
            Task::Shutdown => self.shutdown(event_loop)
        }
    }

    fn timeout(&mut self, event_loop: &mut mio::EventLoop<Client>, task: ScheduledTask) {
        match task {
            ScheduledTask::DeliverMessage(recipient, message) => self.deliver_message(recipient, message, event_loop)
        }
    }
}
<|endoftext|>


<commit_before>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        status_copy.state.open = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .and_then(|people_now_present| {
                match people_now_present[0].value {
                    0i64 => Optional::Value(false),
                    _ => Optional::Value(true),
                }
            }).into();

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), String> {
        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        // TODO: check if key exists and handle errors
        datastore_lock.store(sensor, value);
        Ok(())
    }

    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    fn err_response(&self, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((status::BadRequest, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these println! invocations.
        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response("Too many values specified")),
                },
                None => return Ok(self.err_response("\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        self.update_sensor(&sensor_name, &sensor_value);

        // Create response
        Ok(self.ok_response())
    }

}
<commit_msg>Do proper error handling in update handler<commit_after>//! Handlers for the server.

use std::collections::BTreeMap;

use rustc_serialize::json::{Json, ToJson};
use iron::prelude::*;
use iron::{status, headers, middleware};
use iron::modifiers::Header;
use router::Router;

use urlencoded;

use ::api;
use ::api::optional::Optional;
use ::datastore;
use ::sensors;

#[derive(Debug)]
struct ErrorResponse {
    reason: String,
}

impl ToJson for ErrorResponse {
    /// Serialize an ErrorResponse object into a proper JSON structure.
    fn to_json(&self) -> Json {
        let mut d = BTreeMap::new();
        d.insert("status".to_string(), "error".to_json());
        d.insert("reason".to_string(), self.reason.to_json());
        Json::Object(d)
    }
}

pub struct ReadHandler {
    status: api::Status,
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

impl ReadHandler {
    pub fn new(status: api::Status, datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> ReadHandler {
        ReadHandler {
            status: status,
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    fn build_response_json(&self) -> Json {

        // Create a mutable copy of the status struct
        let mut status_copy = self.status.clone();

        // Process registered sensors
        for sensor_spec in self.sensor_specs.lock().unwrap().iter() {
            sensor_spec.get_sensor_value(self.datastore.clone()).map(|value| {
                if status_copy.sensors.is_absent() {
                    status_copy.sensors = Optional::Value(api::Sensors {
                        people_now_present: Optional::Absent,
                        temperature: Optional::Absent,
                    });
                }
                sensor_spec.template.to_sensor(&value, &mut status_copy.sensors.as_mut().unwrap());
            });
        }

        status_copy.state.open = status_copy.sensors.as_ref()
            .and_then(|sensors| sensors.people_now_present.as_ref())
            .and_then(|people_now_present| {
                match people_now_present[0].value {
                    0i64 => Optional::Value(false),
                    _ => Optional::Value(true),
                }
            }).into();

        // Serialize to JSON
        status_copy.to_json()
    }
}

impl middleware::Handler for ReadHandler {

    /// Return the current status JSON.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get response body
        let body = self.build_response_json().to_string();

        // Create response
        let response = Response::with((status::Ok, body))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any));

        Ok(response)
    }

}

pub struct UpdateHandler {
    datastore: datastore::SafeDataStore,
    sensor_specs: sensors::SafeSensorSpecs,
}

error_type! {
    #[derive(Debug)]
    pub enum UpdateHandlerError {
        UnknownSensor(String) {
            desc (sensor) &sensor;
        },
        DataStoreError(datastore::DataStoreError) {
            cause;
        }
    }
}

impl UpdateHandler {
    pub fn new(datastore: datastore::SafeDataStore, sensor_specs: sensors::SafeSensorSpecs) -> UpdateHandler {
        UpdateHandler {
            datastore: datastore,
            sensor_specs: sensor_specs,
        }
    }

    /// Update sensor value in the `DataStore`
    fn update_sensor(&self, sensor: &str, value: &str) -> Result<(), UpdateHandlerError> {
        // Validate sensor
        try!(self.sensor_specs.lock().unwrap().iter()
                              .find(|&spec| spec.data_key == sensor)
                              .ok_or(UpdateHandlerError::UnknownSensor(sensor.to_string())));

        // Store data to datastore
        let datastore_ref = self.datastore.clone();
        let mut datastore_lock = datastore_ref.lock().unwrap();
        datastore_lock.store(sensor, value)
                      .map(|_| ()).map_err(|e| {
                          error!("Could not update sensor value in datastore: {:?}", e);
                          UpdateHandlerError::DataStoreError(e)
                      })
    }

    /// Build an OK response with the `HTTP 204 No Content` status code.
    fn ok_response(&self) -> Response {
        Response::with((status::NoContent))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

    /// Build an error response with the specified `error_code` and the specified `reason` text.
    fn err_response(&self, error_code: status::Status, reason: &str) -> Response {
        let error = ErrorResponse { reason: reason.to_string() };
        Response::with((error_code, error.to_json().to_string()))
            // Set headers
            .set(Header(headers::ContentType("application/json; charset=utf-8".parse().unwrap())))
            .set(Header(headers::CacheControl(vec![headers::CacheDirective::NoCache])))
            .set(Header(headers::AccessControlAllowOrigin::Any))
    }

}

impl middleware::Handler for UpdateHandler {

    /// Update the sensor, return correct status code.
    fn handle(&self, req: &mut Request) -> IronResult<Response> {

        // TODO: create macro for these println! invocations.
        println!("{} /{} from {}", req.method, req.url.path[0], req.remote_addr);

        // Get sensor name
        let sensor_name;
        {
            // TODO: Properly propagate errors
            let params = req.extensions.get::<Router>().unwrap();
            sensor_name = params.find("sensor").unwrap().to_string();
        }

        // Get sensor value
        let sensor_value;
        {
            let params = req.get_ref::<urlencoded::UrlEncodedBody>().unwrap();
            sensor_value = match params.get("value") {
                Some(ref values) =>  match values.len() {
                    1 => values[0].to_string(),
                    _ => return Ok(self.err_response(status::BadRequest, "Too many values specified")),
                },
                None => return Ok(self.err_response(status::BadRequest, "\"value\" parameter not specified")),
            }
        }

        // Update values in datastore
        if let Err(e) = self.update_sensor(&sensor_name, &sensor_value) {
            error!("update_sensor() failed: {:?}", e);
            let response = match e {
                UpdateHandlerError::UnknownSensor(sensor) =>
                    self.err_response(status::BadRequest, &format!("Unknown sensor: {}", sensor)),
                UpdateHandlerError::DataStoreError(_) =>
                    self.err_response(status::InternalServerError, "Updating values in datastore failed"),
            };
            return Ok(response)
        };

        // Create response
        Ok(self.ok_response())
    }

}
<|endoftext|>


<commit_before>// FIXME To see the "real" compiler error, change both `&'b` and `&'e` into `&`

fn main() { // `'main` starts ────────────────────────────────────────────┐
    let stack_integer: i32 = 5; // `'a` starts ─────────────────────────┐ │
    let boxed_integer = Box::new(4); // `'b` starts ──────────────────┐ │ │
    //                                                                │ │ │
    // This is a valid operation                                      │ │ │
    let ref_to_box: &'b i32 = &*boxed_integer; // `'c` starts ──────┐ │ │ │
    //                                                              │ │ │ │
    // The compiler forbids this operation, because                 │ │ │ │
    // `ref_to_another_box` would become a dangling pointer         │ │ │ │
    let ref_to_another_box: &'e i32 = { // `'let` `'d` start ───┬─┐ │ │ │ │
        let another_boxed_integer = Box::new(3); // ──────────┐ │ │ │ │ │ │
        // ^ `e` starts                                       │ │ │ │ │ │ │
        &*another_boxed_integer //                            │ │ │ │ │ │ │
    }; // `'e` `'let` end ────────────────────────────────────┴─┘ │ │ │ │ │
    //                                                            │ │ │ │ │
    let invalid_dereference = *ref_to_another_box; //             │ │ │ │ │
} // `'d` `'c` `'b` `'a` `'main` end ─────────────────────────────┴─┴─┴─┴─┘
<commit_msg>Changed lifetime names to reflect comments<commit_after>// FIXME To see the "real" compiler error, change both `&'c` and `&'d` into `&`

fn main() { // `'main` starts ────────────────────────────────────────────┐
    let stack_integer: i32 = 5; // `'a` starts ─────────────────────────┐ │
    let boxed_integer = Box::new(4); // `'b` starts ──────────────────┐ │ │
    //                                                                │ │ │
    // This is a valid operation                                      │ │ │
    let ref_to_box: &'c i32 = &*boxed_integer; // `'c` starts ──────┐ │ │ │
    //                                                              │ │ │ │
    // The compiler forbids this operation, because                 │ │ │ │
    // `ref_to_another_box` would become a dangling pointer         │ │ │ │
    let ref_to_another_box: &'d i32 = { // `'let` `'d` start ───┬─┐ │ │ │ │
        let another_boxed_integer = Box::new(3); // ──────────┐ │ │ │ │ │ │
        // ^ `e` starts                                       │ │ │ │ │ │ │
        &*another_boxed_integer //                            │ │ │ │ │ │ │
    }; // `'e` `'let` end ────────────────────────────────────┴─┘ │ │ │ │ │
    //                                                            │ │ │ │ │
    let invalid_dereference = *ref_to_another_box; //             │ │ │ │ │
} // `'d` `'c` `'b` `'a` `'main` end ─────────────────────────────┴─┴─┴─┴─┘
<|endoftext|>