<commit_before>import stackwalk::Word;
import libc::size_t;
import send_map::linear::LinearMap;

export Word;
export gc;
export cleanup_stack_for_failure;

extern mod rustrt {
    fn rust_annihilate_box(ptr: *Word);

    #[rust_stack]
    fn rust_gc_metadata() -> *Word;

    #[rust_stack]
    fn rust_call_tydesc_glue(root: *Word, tydesc: *Word, field: size_t);
}

type SafePoint = { sp_meta: *Word, fn_meta: *Word };

unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
    let module_meta = rustrt::rust_gc_metadata();
    let num_safe_points_ptr: *u32 = unsafe::reinterpret_cast(&module_meta);
    let num_safe_points = *num_safe_points_ptr as Word;
    let safe_points: *Word =
        ptr::offset(unsafe::reinterpret_cast(&module_meta), 1);

    if ptr::is_null(pc) {
        return None;
    }

    let mut sp = 0 as Word;
    while sp < num_safe_points {
        let sp_loc = *ptr::offset(safe_points, sp*3) as *Word;
        if sp_loc == pc {
            return Some(
                {sp_meta: *ptr::offset(safe_points, sp*3 + 1) as *Word,
                 fn_meta: *ptr::offset(safe_points, sp*3 + 2) as *Word});
        }
        sp += 1;
    }
    return None;
}

type Visitor = fn(root: **Word, tydesc: *Word) -> bool;

unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
    let fp_bytes: *u8 = unsafe::reinterpret_cast(&fp);
    let sp_meta_u32s: *u32 = unsafe::reinterpret_cast(&sp.sp_meta);

    let num_stack_roots = *sp_meta_u32s as uint;
    let num_reg_roots = *ptr::offset(sp_meta_u32s, 1) as uint;

    let stack_roots: *u32 =
        unsafe::reinterpret_cast(&ptr::offset(sp_meta_u32s, 2));
    let reg_roots: *u8 =
        unsafe::reinterpret_cast(&ptr::offset(stack_roots, num_stack_roots));
    let addrspaces: *Word =
        unsafe::reinterpret_cast(&ptr::offset(reg_roots, num_reg_roots));
    let tydescs: ***Word =
        unsafe::reinterpret_cast(&ptr::offset(addrspaces, num_stack_roots));

    // Stack roots
    let mut sri = 0;
    while sri < num_stack_roots {
        if *ptr::offset(addrspaces, sri) >= 1 {
            let root =
                ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word)
                as **Word;
            let tydescpp = ptr::offset(tydescs, sri);
            let tydesc = if ptr::is_not_null(tydescpp) &&
                ptr::is_not_null(*tydescpp) {
                **tydescpp
            } else {
                ptr::null()
            };
            if !visitor(root, tydesc) { return; }
        }
        sri += 1;
    }

    // Register roots
    let mut rri = 0;
    while rri < num_reg_roots {
        if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 {
            // FIXME(#2997): Need to find callee saved registers on the stack.
        }
        rri += 1;
    }
}

type Memory = uint;

const task_local_heap: Memory = 1;
const exchange_heap:   Memory = 2;
const stack:           Memory = 4;

const need_cleanup:    Memory = exchange_heap | stack;

unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
    let mut last_ret: *Word = ptr::null();
    // To avoid collecting memory used by the GC itself, skip stack
    // frames until past the root GC stack frame. The root GC stack
    // frame is marked by a sentinel, which is a box pointer stored on
    // the stack.
    let mut reached_sentinel = ptr::is_null(sentinel);
    for stackwalk::walk_stack |frame| {
        unsafe {
            let mut delay_reached_sentinel = reached_sentinel;
            if ptr::is_not_null(last_ret) {
                let sp = is_safe_point(last_ret);
                match sp {
                  Some(sp_info) => {
                    for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
                        // Skip roots until we see the sentinel.
                        if !reached_sentinel {
                            if root == sentinel {
                                delay_reached_sentinel = true;
                            }
                            again;
                        }

                        // Skip null pointers, which can occur when a
                        // unique pointer has already been freed.
                        if ptr::is_null(*root) {
                            again;
                        }

                        if ptr::is_null(tydesc) {
                            // Root is a generic box.
                            let refcount = **root;
                            if mem | task_local_heap != 0 && refcount != -1 {
                                if !visitor(root, tydesc) { return; }
                            } else if mem | exchange_heap != 0
                                && refcount == -1 {
                                if !visitor(root, tydesc) { return; }
                            }
                        } else {
                            // Root is a non-immediate.
                            if mem | stack != 0 {
                                if !visitor(root, tydesc) { return; }
                            }
                        }
                    }
                  }
                  None => ()
                }
            }
            reached_sentinel = delay_reached_sentinel;
            last_ret = *ptr::offset(frame.fp, 1) as *Word;
        }
    }
}

fn gc() {
    unsafe {
        for walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| {
            // FIXME(#2997): Walk roots and mark them.
            io::stdout().write([46]); // .
        }
    }
}

type RootSet = LinearMap<*Word,()>;

fn RootSet() -> RootSet {
    LinearMap()
}

// This should only be called from fail, as it will drop the roots
// which are *live* on the stack, rather than dropping those that are
// dead.
fn cleanup_stack_for_failure() {
    unsafe {
        // Leave a sentinel on the stack to mark the current
        // frame. The stack walker will ignore any frames above the
        // sentinel, thus avoiding collecting any memory being used by
        // the stack walker itself.
        let sentinel_box = ~0;
        let sentinel: **Word =
            unsafe::reinterpret_cast(&ptr::addr_of(sentinel_box));

        let mut roots = ~RootSet();
        for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| {
            // Track roots to avoid double frees.
            if option::is_some(roots.find(&*root)) {
                again;
            }
            roots.insert(*root, ());

            if ptr::is_null(tydesc) {
                rustrt::rust_annihilate_box(*root);
            } else {
                rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
            }
        }
    }
}
<commit_msg>gc: Don't expect sentinel when core is compiled without GC.<commit_after>import stackwalk::Word;
import libc::size_t;
import send_map::linear::LinearMap;

export Word;
export gc;
export cleanup_stack_for_failure;

extern mod rustrt {
    fn rust_annihilate_box(ptr: *Word);

    #[rust_stack]
    fn rust_gc_metadata() -> *Word;

    #[rust_stack]
    fn rust_call_tydesc_glue(root: *Word, tydesc: *Word, field: size_t);
}

type SafePoint = { sp_meta: *Word, fn_meta: *Word };

unsafe fn is_safe_point(pc: *Word) -> Option<SafePoint> {
    let module_meta = rustrt::rust_gc_metadata();
    let num_safe_points_ptr: *u32 = unsafe::reinterpret_cast(&module_meta);
    let num_safe_points = *num_safe_points_ptr as Word;
    let safe_points: *Word =
        ptr::offset(unsafe::reinterpret_cast(&module_meta), 1);

    if ptr::is_null(pc) {
        return None;
    }

    let mut sp = 0 as Word;
    while sp < num_safe_points {
        let sp_loc = *ptr::offset(safe_points, sp*3) as *Word;
        if sp_loc == pc {
            return Some(
                {sp_meta: *ptr::offset(safe_points, sp*3 + 1) as *Word,
                 fn_meta: *ptr::offset(safe_points, sp*3 + 2) as *Word});
        }
        sp += 1;
    }
    return None;
}

type Visitor = fn(root: **Word, tydesc: *Word) -> bool;

unsafe fn walk_safe_point(fp: *Word, sp: SafePoint, visitor: Visitor) {
    let fp_bytes: *u8 = unsafe::reinterpret_cast(&fp);
    let sp_meta_u32s: *u32 = unsafe::reinterpret_cast(&sp.sp_meta);

    let num_stack_roots = *sp_meta_u32s as uint;
    let num_reg_roots = *ptr::offset(sp_meta_u32s, 1) as uint;

    let stack_roots: *u32 =
        unsafe::reinterpret_cast(&ptr::offset(sp_meta_u32s, 2));
    let reg_roots: *u8 =
        unsafe::reinterpret_cast(&ptr::offset(stack_roots, num_stack_roots));
    let addrspaces: *Word =
        unsafe::reinterpret_cast(&ptr::offset(reg_roots, num_reg_roots));
    let tydescs: ***Word =
        unsafe::reinterpret_cast(&ptr::offset(addrspaces, num_stack_roots));

    // Stack roots
    let mut sri = 0;
    while sri < num_stack_roots {
        if *ptr::offset(addrspaces, sri) >= 1 {
            let root =
                ptr::offset(fp_bytes, *ptr::offset(stack_roots, sri) as Word)
                as **Word;
            let tydescpp = ptr::offset(tydescs, sri);
            let tydesc = if ptr::is_not_null(tydescpp) &&
                ptr::is_not_null(*tydescpp) {
                **tydescpp
            } else {
                ptr::null()
            };
            if !visitor(root, tydesc) { return; }
        }
        sri += 1;
    }

    // Register roots
    let mut rri = 0;
    while rri < num_reg_roots {
        if *ptr::offset(addrspaces, num_stack_roots + rri) == 1 {
            // FIXME(#2997): Need to find callee saved registers on the stack.
        }
        rri += 1;
    }
}

type Memory = uint;

const task_local_heap: Memory = 1;
const exchange_heap:   Memory = 2;
const stack:           Memory = 4;

const need_cleanup:    Memory = exchange_heap | stack;

unsafe fn walk_gc_roots(mem: Memory, sentinel: **Word, visitor: Visitor) {
    let mut last_ret: *Word = ptr::null();
    // To avoid collecting memory used by the GC itself, skip stack
    // frames until past the root GC stack frame. The root GC stack
    // frame is marked by a sentinel, which is a box pointer stored on
    // the stack.
    let mut reached_sentinel = ptr::is_null(sentinel);
    for stackwalk::walk_stack |frame| {
        unsafe {
            let mut delay_reached_sentinel = reached_sentinel;
            if ptr::is_not_null(last_ret) {
                let sp = is_safe_point(last_ret);
                match sp {
                  Some(sp_info) => {
                    for walk_safe_point(frame.fp, sp_info) |root, tydesc| {
                        // Skip roots until we see the sentinel.
                        if !reached_sentinel {
                            if root == sentinel {
                                delay_reached_sentinel = true;
                            }
                            again;
                        }

                        // Skip null pointers, which can occur when a
                        // unique pointer has already been freed.
                        if ptr::is_null(*root) {
                            again;
                        }

                        if ptr::is_null(tydesc) {
                            // Root is a generic box.
                            let refcount = **root;
                            if mem | task_local_heap != 0 && refcount != -1 {
                                if !visitor(root, tydesc) { return; }
                            } else if mem | exchange_heap != 0
                                && refcount == -1 {
                                if !visitor(root, tydesc) { return; }
                            }
                        } else {
                            // Root is a non-immediate.
                            if mem | stack != 0 {
                                if !visitor(root, tydesc) { return; }
                            }
                        }
                    }
                  }
                  None => ()
                }
            }
            reached_sentinel = delay_reached_sentinel;
            last_ret = *ptr::offset(frame.fp, 1) as *Word;
        }
    }
}

fn gc() {
    unsafe {
        for walk_gc_roots(task_local_heap, ptr::null()) |_root, _tydesc| {
            // FIXME(#2997): Walk roots and mark them.
            io::stdout().write([46]); // .
        }
    }
}

type RootSet = LinearMap<*Word,()>;

fn RootSet() -> RootSet {
    LinearMap()
}

#[cfg(gc)]
fn expect_sentinel() -> bool { true }

#[cfg(nogc)]
fn expect_sentinel() -> bool { false }

// This should only be called from fail, as it will drop the roots
// which are *live* on the stack, rather than dropping those that are
// dead.
fn cleanup_stack_for_failure() {
    unsafe {
        // Leave a sentinel on the stack to mark the current frame. The
        // stack walker will ignore any frames above the sentinel, thus
        // avoiding collecting any memory being used by the stack walker
        // itself.
        //
        // However, when core itself is not compiled with GC, then none of
        // the functions in core will have GC metadata, which means we
        // won't be able to find the sentinel root on the stack. In this
        // case, we can safely skip the sentinel since we won't find our
        // own stack roots on the stack anyway.
        let sentinel_box = ~0;
        let sentinel: **Word = if expect_sentinel() {
            unsafe::reinterpret_cast(&ptr::addr_of(sentinel_box))
        } else {
            ptr::null()
        };

        let mut roots = ~RootSet();
        for walk_gc_roots(need_cleanup, sentinel) |root, tydesc| {
            // Track roots to avoid double frees.
            if option::is_some(roots.find(&*root)) {
                again;
            }
            roots.insert(*root, ());

            if ptr::is_null(tydesc) {
                rustrt::rust_annihilate_box(*root);
            } else {
                rustrt::rust_call_tydesc_glue(*root, tydesc, 3 as size_t);
            }
        }
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 Dmytro Milinevskyi <dmilinevskyi@gmail.com>

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std;

use levels::LogLevel;

/// The markers of the begging of the file and its end.
pub enum LineRangeBound {
    /// Beginning of the file.
    BOF,
    /// End of the file.
    EOF,
}

impl From<LineRangeBound> for u32 {
    #[inline(always)]
    fn from(orig: LineRangeBound) -> u32 {
        match orig {
            LineRangeBound::BOF => 0,
            LineRangeBound::EOF => std::u32::MAX,
        }
    }
}

#[doc(hidden)]
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
pub struct LineRangeSpec {
    pub level: LogLevel,
    pub from: u32,
    pub to: u32,
}

#[doc(hidden)]
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
pub enum LineRangeError {
    InvalidRange(u32, u32),
}

impl LineRangeSpec {
    #[doc(hidden)]
    #[inline(always)]
    pub fn new(level: LogLevel, from: u32, to: u32) -> Result<Self, LineRangeError> {
        if from > to {
            Err(LineRangeError::InvalidRange(from, to))
        } else {
            Ok(LineRangeSpec {
                level: level,
                from: from,
                to: to,
            })
        }
    }
}

impl ToString for LineRangeError {
    fn to_string(&self) -> String {
        match *self {
            LineRangeError::InvalidRange(from, to) => format!("Invalid range [{}; {}]", from, to),
        }
    }
}

#[doc(hidden)]
pub fn prepare_ranges(level: LogLevel, lranges: &[(u32, u32)]) -> Result<Vec<LineRangeSpec>, LineRangeError> {
    let (lranges, fails): (Vec<_>, Vec<_>) = lranges.iter()
        .map(|&(from, to)| LineRangeSpec::new(level, from, to))
        .partition(Result::is_ok);
    if !fails.is_empty() {
        let err = fails.first().unwrap().clone();
        return Err(err.unwrap_err());
    }

    let mut lranges: Vec<_> = lranges.into_iter().map(Result::unwrap).collect();
    lranges.sort_by_key(|k| k.from);

    // FIXME: merge the ranges

    if lranges.len() == 1 {
        let bof: u32 = LineRangeBound::BOF.into();
        let eof: u32 = LineRangeBound::EOF.into();
        let first = lranges.first().unwrap().clone();
        if first.from == bof && first.to == eof {
            lranges.clear();
        }
    }

    Ok(lranges)
}
<commit_msg>clippy suggestions<commit_after>// Copyright 2017 Dmytro Milinevskyi <dmilinevskyi@gmail.com>

// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at

// http://www.apache.org/licenses/LICENSE-2.0

// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std;

use levels::LogLevel;

/// The markers of the begging of the file and its end.
pub enum LineRangeBound {
    /// Beginning of the file.
    BOF,
    /// End of the file.
    EOF,
}

impl From<LineRangeBound> for u32 {
    #[inline(always)]
    fn from(orig: LineRangeBound) -> u32 {
        match orig {
            LineRangeBound::BOF => 0,
            LineRangeBound::EOF => std::u32::MAX,
        }
    }
}

#[doc(hidden)]
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
pub struct LineRangeSpec {
    pub level: LogLevel,
    pub from: u32,
    pub to: u32,
}

#[doc(hidden)]
#[derive(PartialEq, PartialOrd, Clone, Copy, Debug)]
pub enum LineRangeError {
    InvalidRange(u32, u32),
}

impl LineRangeSpec {
    #[doc(hidden)]
    #[inline(always)]
    pub fn new(level: LogLevel, from: u32, to: u32) -> Result<Self, LineRangeError> {
        if from > to {
            Err(LineRangeError::InvalidRange(from, to))
        } else {
            Ok(LineRangeSpec {
                level: level,
                from: from,
                to: to,
            })
        }
    }
}

impl ToString for LineRangeError {
    fn to_string(&self) -> String {
        match *self {
            LineRangeError::InvalidRange(from, to) => format!("Invalid range [{}; {}]", from, to),
        }
    }
}

#[doc(hidden)]
pub fn prepare_ranges(level: LogLevel, lranges: &[(u32, u32)]) -> Result<Vec<LineRangeSpec>, LineRangeError> {
    let (lranges, fails): (Vec<_>, Vec<_>) = lranges.iter()
        .map(|&(from, to)| LineRangeSpec::new(level, from, to))
        .partition(Result::is_ok);
    if !fails.is_empty() {
        let err = *fails.first().unwrap();
        return Err(err.unwrap_err());
    }

    let mut lranges: Vec<_> = lranges.into_iter().map(Result::unwrap).collect();
    lranges.sort_by_key(|k| k.from);

    // FIXME: merge the ranges

    if lranges.len() == 1 {
        let bof: u32 = LineRangeBound::BOF.into();
        let eof: u32 = LineRangeBound::EOF.into();
        let first = *lranges.first().unwrap();
        if first.from == bof && first.to == eof {
            lranges.clear();
        }
    }

    Ok(lranges)
}
<|endoftext|>


<commit_before>// -*- rust -*-
// xfail-test
// error-pattern:Unsatisfied precondition

pure fn less_than(x: int, y: int) -> bool { ret x < y; }

type ordered_range = {low: int, high: int} : less_than(low, high);

fn main() {
    // Should fail to compile, b/c we're not doing the check
    // explicitly that a < b
    let a: int = 1;
    let b: int = 2;
    let c: ordered_range = {low: a, high: b};
    log c.low;
}<commit_msg>Fix parse error in constrained-type-missing-check.rs<commit_after>// -*- rust -*-
// xfail-test
// error-pattern:Unsatisfied precondition

pure fn less_than(x: int, y: int) -> bool { ret x < y; }

type ordered_range = {low: int, high: int} : less_than(*.low, *.high);

fn main() {
    // Should fail to compile, b/c we're not doing the check
    // explicitly that a < b
    let a: int = 1;
    let b: int = 2;
    let c: ordered_range = {low: a, high: b};
    log c.low;
}
<|endoftext|>


<commit_before>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new<'r>(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    path.exists()
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let home_unwrap = homedir().unwrap();
  let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<commit_msg>Remove lifetime value.<commit_after>use std::io::{File,fs};
use std::path::posix::Path;
use std::os::{homedir};
use std::rand::random;

pub fn new(name: &str) {
    let home_unwrap = homedir().unwrap();
    let path = format!("{}/.muxed/{}", home_unwrap.display(), name);
    File::create(&Path::new(path));
}

fn create_muxed_dir(name: &String) -> Path {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    fs::mkdir(path, ::std::io::UserRWX);
    path.clone()
}

fn muxed_dir_exists(name: &String) -> bool {
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.{}", home_unwrap.display(), name));
    path.exists()
}

#[test]
fn muxed_dir_exists_returns_false() {
  let dir = format!("test_dir_{}", random::<f64>());
  assert!(!muxed_dir_exists(&dir));
}

#[test]
fn muxed_dir_exists_returns_true() {
  let dir = format!("test_dir_{}", random::<f64>());
  create_muxed_dir(&dir);
  assert!(muxed_dir_exists(&dir));

  let home_unwrap = homedir().unwrap();
  let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
  fs::rmdir_recursive(muxed_path);
}

#[test]
fn creates_muxed_dir() {
    let name        = format!("test_project_{}", random::<f64>());
    let dir         = format!("test_dir_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let muxed_path  = &Path::new(format!("{}/.{}/", home_unwrap.display(), dir.as_slice()));
    create_muxed_dir(&dir);
    assert!(muxed_path.exists());
    fs::rmdir_recursive(muxed_path);
}

#[test]
fn new_writes_file_to_muxed_dir() {
    let name = format!("test_project_{}", random::<f64>());
    let home_unwrap = homedir().unwrap();
    let path = &Path::new(format!("{}/.muxed/{}", home_unwrap.display(), name));
    new(name.as_slice());
    assert!(path.exists());
    fs::unlink(path);
}
<|endoftext|>


<commit_before>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<commit_msg>Decode OSC True, False, Nil and Infinity<commit_after>use types::{OscPacket, OscType, OscResult, OscMessage, OscMidiMessage, OscBundle};
use errors::OscError;
use utils;

use std::{io, char};
use std::io::{Read, BufRead};

use byteorder::{BigEndian, ReadBytesExt};

/// Common MTP size for ethernet
pub const MTP: usize = 1536;

pub fn decode(msg: &[u8]) -> OscResult<OscPacket> {
    match msg[0] as char {
        '/' => {
            decode_message(msg)
        }
        '#' => {
            decode_bundle(msg)
        }
        _ => Err(OscError::BadPacket("Unknown message format.".to_string())),
    }
}

fn decode_message(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let addr: String = try!(read_osc_string(&mut cursor));
    let type_tags: String = try!(read_osc_string(&mut cursor));

    if type_tags.len() > 1 {
        let args: Vec<OscType> = try!(read_osc_args(&mut cursor, type_tags));

        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: Some(args),
        }))
    } else {
        Ok(OscPacket::Message(OscMessage {
            addr: addr,
            args: None,
        }))
    }
}

fn decode_bundle(msg: &[u8]) -> OscResult<OscPacket> {
    let mut cursor: io::Cursor<&[u8]> = io::Cursor::new(msg);

    let b = try!(read_osc_string(&mut cursor));
    if b != "bundle" {
        return Err(OscError::BadBundle);
    }

    let time_tag = try!(read_time_tag(&mut cursor));
    let mut bundle: Vec<OscPacket> = Vec::new();
    let size: usize = try!(cursor.read_u32::<BigEndian>()
                                 .map_err(OscError::ByteOrderError)) as usize;
    let mut buf: Vec<u8> = Vec::new();
    let cnt: usize = try!(cursor.take(size as u64)
                                .read_to_end(&mut buf)
                                .map_err(OscError::ReadError));
    if cnt == size {
        try!(decode(&mut buf).map(|p| bundle.push(p)));
    } else {
        return Err(OscError::BadBundle);
    }

    Ok(OscPacket::Bundle(OscBundle {
        timetag: time_tag,
        content: bundle,
    }))
}

fn read_osc_string(cursor: &mut io::Cursor<&[u8]>) -> OscResult<String> {
    let mut str_buf: Vec<u8> = Vec::new();
    try!(cursor.read_until(0, &mut str_buf)
               .map_err(OscError::ReadError)); // ignore returned byte count
    pad_cursor(cursor);
    // convert to String and remove nul bytes
    String::from_utf8(str_buf)
        .map_err(|e| OscError::StringError(e))
        .map(|s| {
            s.trim_matches(0u8 as char)
             .to_string()
        })
}

fn read_osc_args(cursor: &mut io::Cursor<&[u8]>, raw_type_tags: String) -> OscResult<Vec<OscType>> {
    let type_tags: Vec<char> = raw_type_tags.chars()
                                            .skip(1)
                                            .map(|c| c as char)
                                            .collect();
    let mut args: Vec<OscType> = Vec::with_capacity(type_tags.len());
    for tag in type_tags {
        let arg: OscType = try!(read_osc_arg(cursor, tag));
        args.push(arg);
    }
    Ok(args)
}

fn read_osc_arg(cursor: &mut io::Cursor<&[u8]>, tag: char) -> OscResult<OscType> {
    match tag {
        'f' => {
            cursor.read_f32::<BigEndian>()
                  .map(OscType::Float)
                  .map_err(OscError::ByteOrderError)
        }
        'd' => {
            cursor.read_f64::<BigEndian>()
                  .map(OscType::Double)
                  .map_err(OscError::ByteOrderError)
        }
        'i' => {
            cursor.read_i32::<BigEndian>()
                  .map(OscType::Int)
                  .map_err(OscError::ByteOrderError)
        }
        'h' => {
            cursor.read_i64::<BigEndian>()
                  .map(OscType::Long)
                  .map_err(OscError::ByteOrderError)
        }
        's' => {
            read_osc_string(cursor).map(|s| OscType::String(s))
        }
        't' => {
            // http://opensoundcontrol.org/node/3/#timetags
            read_time_tag(cursor)
        }
        'b' => {
            let size: usize =
                try!(cursor.read_u32::<BigEndian>()
                           .map_err(OscError::ByteOrderError)) as usize;
            let mut byte_buf: Vec<u8> = Vec::with_capacity(size);
            try!(cursor.take(size as u64)
                       .read_to_end(&mut byte_buf)
                       .map_err(OscError::ReadError));
            pad_cursor(cursor);
            Ok(OscType::Blob(byte_buf))

        }
        'T' => {
            Ok(OscType::Bool(true))
        }
        'F' => {
            Ok(OscType::Bool(false))
        }
        'N' => {
            Ok(OscType::Nil)
        }
        'I' => {
            Ok(OscType::Inf)
        }
        'c' => {
            let opt_char = try!(cursor.read_u32::<BigEndian>()
                                      .map(char::from_u32)
                                      .map_err(OscError::ByteOrderError));
            match opt_char {
                Some(c) => Ok(OscType::Char(c)),
                None => Err(OscError::BadArg("Argument is not a char!".to_string())),
            }
        }
        'm' => {
            read_midi_message(cursor)
        }
        _ => Err(OscError::BadArg(format!("Type tag \"{}\" is not implemented!", tag))),
    }
}

fn read_time_tag(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    match cursor.read_u32::<BigEndian>() {
        Ok(date) => {
            match cursor.read_u32::<BigEndian>() {
                Ok(frac) => Ok(OscType::Time(date, frac)),
                Err(e) => Err(OscError::ByteOrderError(e)),
            }
        }
        Err(e) => Err(OscError::ByteOrderError(e)),
    }

fn read_midi_message(cursor: &mut io::Cursor<&[u8]>) -> OscResult<OscType> {
    let mut buf: Vec<u8> = Vec::with_capacity(4);
    try!(cursor.take(4).read_to_end(&mut buf).map_err(OscError::ReadError));

    Ok(OscType::Midi(OscMidiMessage {
        port: buf[0],
        status: buf[1],
        data1: buf[2],
        data2: buf[3],
    }))

}

fn pad_cursor(cursor: &mut io::Cursor<&[u8]>) {
    let pos = cursor.position();
    cursor.set_position(utils::pad(pos));
}
<|endoftext|>


<commit_before>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    tags: Vec<String>,

    /// An id unique to this node.
    id: NodeId,

    /// Services connected directly to this node.
    inputs: Vec<Service<Input>>,
    outputs: Vec<Service<Output>>,
}

impl Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this node.
    pub fn get_id<'a>(&'a self) -> &'a NodeId {
        &self.id
    }

    /// Input services connected directly to this node.
    pub fn get_inputs<'a>(&'a self) -> &'a Vec<Service<Input>> {
        &self.inputs
    }

    /// Output services connected directly to this node.
    pub fn get_outputs<'a>(&'a self) -> &'a Vec<Service<Output>> {
        &self.outputs
    }
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
//
// Important: If you add constructors, don't forget to update `from_string`.
//
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }

    pub fn from_string(s: String) -> Option<Self> {
        use self::ServiceKind::*;
        match &*s {
            "Ready" => Some(Ready),
            "OnOff" => Some(OnOff),
            "OpenClosed" => Some(OpenClosed),
            "CurrentTime" => Some(CurrentTime),
            "CurrentTimeOfDay" => Some(CurrentTimeOfDay),
            "RemainingTime" => Some(RemainingTime),
            "Thermostat" => Some(Thermostat),
            "ActualTemperature" => Some(ActualTemperature),
            _ => None,
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    updated: TimeStamp,
}
impl IOMechanism for Input {
}
impl Input {
    /// The kind of value that can be obtained from this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    pub fn get_poll(&self) -> Option<ValDuration> {
        self.poll.clone()
    }

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    pub fn get_trigger(&self) -> Option<ValDuration> {
        self.trigger.clone()
    }

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    updated: TimeStamp,
}
impl IOMechanism for Output {
}
impl Output {
    /// The kind of value that can be sent to this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    pub fn get_push(&self) -> Option<ValDuration> {
        self.push.clone()
    }

    /// Date at which the latest value was sent.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    tags: Vec<String>,

    /// An id unique to this service.
    id: ServiceId,

    /// The node owning this service.
    node: NodeId,

    /// The update mechanism for this service.
    mechanism: IO,

    /// The last time the device was seen.
    last_seen: TimeStamp,
}

impl<IO> Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this service.
    pub fn get_id<'a>(&'a self) -> &'a ServiceId {
        &self.id
    }

    /// The node owning this service.
    pub fn get_node_id<'a>(&'a self) -> &'a NodeId {
        &self.node
    }

    /// The update mechanism for this service.
    pub fn get_mechanism<'a>(&'a self) -> &'a IO {
        &self.mechanism
    }

    /// The last time the device was seen.
    pub fn get_last_seen(&self) -> TimeStamp {
        self.last_seen.clone()
    }
}

/// A mechanism used for communicating between the application and the
/// service.
pub trait IOMechanism: Deserialize + Serialize {
}

<commit_msg>NodeId, ServiceId now implement Eq<commit_after>//! This module defines the metadata on devices and services.
//!
//! Note that all the data structures in this module represent
//! snapshots of subsets of the devices available. None of these data
//! structures are live, so there is always the possibility that
//! devices may have been added or removed from the FoxBox by the time
//! these data structures are read.

use values::*;

use serde::ser::{Serialize, Serializer};
use serde::de::{Deserialize, Deserializer, Error};

/// The unique Id of a node on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct NodeId(String);
impl NodeId {
    pub fn new(id: String) -> Self {
        NodeId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// Metadata on a node. A node is a device or collection of devices
/// that may offer services. The FoxBox itself a node offering
/// services such as a clock, communication with the user through her
/// smart devices, etc.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications to find nodes and
    /// services.
    ///
    /// For instance, a user may set tag "entrance" to all nodes
    /// placed in the entrance of his house, or a tag "blue" to a node
    /// controlling blue lights. An adapter may set tags "plugged" or
    /// "battery" to devices that respectively depend on a plugged
    /// power source or on a battery.
    tags: Vec<String>,

    /// An id unique to this node.
    id: NodeId,

    /// Services connected directly to this node.
    inputs: Vec<Service<Input>>,
    outputs: Vec<Service<Output>>,
}

impl Node {
    /// Tags describing the node.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used by applications.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this node.
    pub fn get_id<'a>(&'a self) -> &'a NodeId {
        &self.id
    }

    /// Input services connected directly to this node.
    pub fn get_inputs<'a>(&'a self) -> &'a Vec<Service<Input>> {
        &self.inputs
    }

    /// Output services connected directly to this node.
    pub fn get_outputs<'a>(&'a self) -> &'a Vec<Service<Output>> {
        &self.outputs
    }
}

/// The unique Id of a service on the network.
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize, Hash, Eq)]
pub struct ServiceId(String);
impl ServiceId {
    pub fn new(id: String) -> Self {
        ServiceId(id)
    }
    pub fn as_string(&self) -> &String {
        &self.0
    }
}

/// The kind of the service, i.e. a strongly-typed description of
/// _what_ the service can do. Used both for locating services
/// (e.g. "I need a clock" or "I need something that can provide
/// pictures") and for determining the data structure that these
/// services can provide or consume.
///
/// A number of service kinds are standardized, and provided as a set
/// of strongly-typed enum constructors. It is clear, however, that
/// many devices will offer services that cannot be described by
/// pre-existing constructors. For this purpose, this enumeration
/// offers a constructor `Extension`, designed to describe novel
/// services.
//
// Important: If you add constructors, don't forget to update `from_string`.
//
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
pub enum ServiceKind {
    ///
    /// # No payload
    ///

    /// The service is ready. Used for instance once a countdown has
    /// reached completion.
    Ready,

    ///
    /// # Boolean
    ///

    /// The service is used to detect or decide whether some device
    /// is on or off.
    OnOff,

    /// The service is used to detect or decide whether some device
    /// is open or closed.
    OpenClosed,

    ///
    /// # Time
    ///

    /// The service is used to read or set the current absolute time.
    /// Used for instance to wait until a specific time and day before
    /// triggering an action, or to set the appropriate time on a new
    /// device.
    CurrentTime,

    /// The service is used to read or set the current time of day.
    /// Used for instance to trigger an action at a specific hour
    /// every day.
    CurrentTimeOfDay,

    /// The service is part of a countdown. This is the time
    /// remaining until the countdown is elapsed.
    RemainingTime,

    ///
    /// # Temperature
    ///

    Thermostat,
    ActualTemperature,

    /// TODO: Add more

    /// An operation of a kind that has not been standardized yet.
    Extension {
        /// The vendor. Used for namespacing purposes, to avoid
        /// confusing two incompatible extensions with similar
        /// names. For instance, "foxlink@mozilla.com".
        vendor: String,

        /// Identification of the adapter introducing this operation.
        /// Designed to aid with tracing and debugging.
        adapter: String,

        /// A string describing the nature of the value, designed to
        /// let applications discover the devices.
        ///
        /// Examples: `"GroundHumidity"`.
        kind: String,

        /// The data type of the value.
        typ: Type
    }
}

impl ServiceKind {
    /// Get the type of values used to communicate with this service.
    pub fn get_type(&self) -> Type {
        use self::ServiceKind::*;
        use values::Type::*;
        match *self {
            Ready => Unit,
            OnOff | OpenClosed => Bool,
            CurrentTime => TimeStamp,
            CurrentTimeOfDay | RemainingTime => Duration,
            Thermostat | ActualTemperature => Temperature,
            Extension { ref typ, ..} => typ.clone(),
        }
    }

    pub fn from_string(s: String) -> Option<Self> {
        use self::ServiceKind::*;
        match &*s {
            "Ready" => Some(Ready),
            "OnOff" => Some(OnOff),
            "OpenClosed" => Some(OpenClosed),
            "CurrentTime" => Some(CurrentTime),
            "CurrentTimeOfDay" => Some(CurrentTimeOfDay),
            "RemainingTime" => Some(RemainingTime),
            "Thermostat" => Some(Thermostat),
            "ActualTemperature" => Some(ActualTemperature),
            _ => None,
        }
    }
}

/// An input operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Input {
    /// The kind of value that can be obtained from this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    #[serde(default)]
    poll: Option<ValDuration>,

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    #[serde(default)]
    trigger: Option<ValDuration>,

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    updated: TimeStamp,
}
impl IOMechanism for Input {
}
impl Input {
    /// The kind of value that can be obtained from this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service can be polled, i.e. it
    /// will respond when the FoxBox requests the latest value.
    /// Parameter `duration` indicates the smallest interval
    /// between two updates.
    ///
    /// Otherwise, the service cannot be polled and will push
    /// data to the FoxBox when it is available.
    ///
    /// # Examples
    ///
    /// - Long-running pollution or humidity sensors typically
    ///   do not accept requests and rather send batches of
    ///   data every 24h.
    pub fn get_poll(&self) -> Option<ValDuration> {
        self.poll.clone()
    }

    /// If `Some(duration)`, this service can send the data to
    /// the FoxBox whenever it is updated. Parameter `duration`
    /// indicates the smallest interval between two updates.
    ///
    /// Otherwise, the service cannot send data to the FoxBox
    /// and needs to be polled.
    pub fn get_trigger(&self) -> Option<ValDuration> {
        self.trigger.clone()
    }

    /// Date at which the latest value was received, whether through
    /// polling or through a trigger.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An output operation available on an service.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Output {
    /// The kind of value that can be sent to this service.
    kind: ServiceKind,

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    #[serde(default)]
    push: Option<ValDuration>,

    /// Date at which the latest value was sent to the service.
    updated: TimeStamp,
}
impl IOMechanism for Output {
}
impl Output {
    /// The kind of value that can be sent to this service.
    pub fn get_kind(&self) -> ServiceKind {
        self.kind.clone()
    }

    /// If `Some(duration)`, this service supports pushing,
    /// i.e. the FoxBox can send values.
    pub fn get_push(&self) -> Option<ValDuration> {
        self.push.clone()
    }

    /// Date at which the latest value was sent.
    ///
    /// # Limitation
    ///
    /// This is *not* a live view.
    pub fn get_updated(&self) -> TimeStamp {
        self.updated.clone()
    }
}

/// An service represents a single place where data can enter or
/// leave a device. Note that services support either a single kind
/// of input or a single kind of output. Devices that support both
/// inputs or outputs, or several kinds of inputs, or several kinds of
/// outputs, are represented as nodes containing several services.
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    #[serde(default)]
    tags: Vec<String>,

    /// An id unique to this service.
    id: ServiceId,

    /// The node owning this service.
    node: NodeId,

    /// The update mechanism for this service.
    mechanism: IO,

    /// The last time the device was seen.
    last_seen: TimeStamp,
}

impl<IO> Service<IO> where IO: IOMechanism {
    /// Tags describing the service.
    ///
    /// These tags can be set by the user, adapters or
    /// applications. They are used to regroup services for rules.
    ///
    /// For instance "entrance".
    pub fn get_tags<'a>(&'a self) -> &'a Vec<String> {
        &self.tags
    }

    /// An id unique to this service.
    pub fn get_id<'a>(&'a self) -> &'a ServiceId {
        &self.id
    }

    /// The node owning this service.
    pub fn get_node_id<'a>(&'a self) -> &'a NodeId {
        &self.node
    }

    /// The update mechanism for this service.
    pub fn get_mechanism<'a>(&'a self) -> &'a IO {
        &self.mechanism
    }

    /// The last time the device was seen.
    pub fn get_last_seen(&self) -> TimeStamp {
        self.last_seen.clone()
    }
}

/// A mechanism used for communicating between the application and the
/// service.
pub trait IOMechanism: Deserialize + Serialize {
}

<|endoftext|>


<commit_before>extern crate file_api;
extern crate futures;
extern crate hyper;

use std::thread;
use std::io::Read;
use std::io::Write;
use std::io::SeekFrom;
use std::net::TcpListener;
use std::time::Duration;

use futures::channel::mpsc;

use file_api::http_reader::HttpReader;
use file_api::reader::Reader;

fn mock_server(port: &str, messages: Vec<String>, tester: &mut FnMut()) {
    let mut responses = messages.clone();
    responses.reverse();

    let address = ["127.0.0.1:", port].join("");
    let server = TcpListener::bind(address).unwrap();

    let (mut tx, _rx) = mpsc::channel(messages.len());
    let handler = thread::spawn(move || {
        while responses.len() != 0 {
            match responses.pop() {
                Some(response) => {
                    let mut inc = server.accept().unwrap().0;
                    inc.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
                    inc.set_write_timeout(Some(Duration::from_secs(5))).unwrap();

                    let mut message = "".to_string();
                    let _result = inc.read_to_string(&mut message);
                    // println!("{:?} ==> {:?}", message, response);

                    if message != "" {
                        inc.write_all(response.as_ref()).unwrap();
                        let _ = tx.start_send(());
                    }
                }
                None => {}
            }
        }
    });

    tester();
    handler.join().unwrap();
}

macro_rules! assert_position {
  ($reader:expr, $position:expr) => {
    {
      let position = $reader.get_position().unwrap();
      assert_eq!(position, $position);
    }
  };
}
macro_rules! assert_buffer_position {
  ($reader:expr, $position:expr) => {
    {
      assert_eq!($reader.buffer.position, $position);
    }
  };
}
macro_rules! assert_next_data {
  ($reader:expr, $string_data:expr) => {
    {
      let length = $string_data.len();
      let data = $reader.read(length).unwrap();
      assert_eq!(data.len(), length);
      let data_str = std::str::from_utf8(&data).unwrap();
      assert!(data_str == $string_data);
    }
  };
}

#[test]
fn http_exists() {
    let responses = vec!["HTTP/1.1 200 OK\n\n".to_string()];

    fn check() {
        let file = "http://127.0.0.1:8880".to_string();
        assert!(file_api::exists(&file) == true);
    }

    mock_server("8880", responses, &mut check);
}

#[test]
fn http_not_exists() {
    let responses = vec!["HTTP/1.1 404 OK\n\n".to_string()];

    fn check() {
        let file = "http://127.0.0.1:8881".to_string();
        assert!(file_api::exists(&file) == false);
    }

    mock_server("8881", responses, &mut check);
}

#[test]
fn http_size() {
    let responses = vec!["HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string()];

    fn check() {
        let filename = "http://127.0.0.1:8882".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        let size = reader.get_size().unwrap();
        assert_eq!(size, 19);
    }

    mock_server("8882", responses, &mut check);
}

#[test]
fn http_read_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Range: bytes 0-3/19\r\n\r\nsome"
            .to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Range: bytes 4-7/19\r\n\r\ndata"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8883/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        assert_position!(reader, 0);
        assert_next_data!(reader, "some".to_string());
        assert_position!(reader, 4);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
    }

    mock_server("8883", responses, &mut check);
}

#[test]
fn http_read_buffered_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 12\r\nContent-Range: bytes 0-11/19\r\n\r\nsomedatanext"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8884/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        reader.set_cache_size(Some(12));

        assert_position!(reader, 0);
        assert_buffer_position!(reader, 0);
        assert_next_data!(reader, "some".to_string());
        assert_position!(reader, 4);
        assert_buffer_position!(reader, 12);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
        assert_buffer_position!(reader, 12);

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(10));

        assert_position!(reader, 10);
        assert_buffer_position!(reader, 12);

        assert_next_data!(reader, "xt".to_string());
        assert_position!(reader, 12);
        assert_buffer_position!(reader, 12);
    }

    mock_server("8884", responses, &mut check);
}

#[test]
fn http_read_and_seek_buffered_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nContent-Range: bytes 4-11/19\r\n\r\ndatanext"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8885/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(2));

        reader.set_cache_size(Some(8));

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(4));

        assert_position!(reader, 4);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
        assert_next_data!(reader, "next".to_string());
        assert_position!(reader, 12);
    }

    mock_server("8885", responses, &mut check);
}

#[test]
fn http_seek() {
    let responses = vec!["HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string()];
    fn check() {
        let filename = "http://127.0.0.1:8886/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        assert_position!(reader, 0);
        let position = reader.seek(SeekFrom::Current(4)).unwrap();
        assert_eq!(position, 4);
        assert_position!(reader, 4);
    }

    mock_server("8886", responses, &mut check);
}

#[test]
fn http_read_and_return_different_buffer_size() {
    let responses = vec![
    "HTTP/1.1 200 OK\r\nContent-Length: 19000\r\n\r\n".to_string(),
    "HTTP/1.1 200 OK\r\nContent-Length: 12\r\nContent-Range: bytes 0-12/19000\r\n\r\nsomedatanext".to_string(),
  ];

    fn check() {
        let filename = "http://127.0.0.1:8887/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        reader.set_cache_size(Some(100));
        assert_next_data!(reader, "somedata");

        assert_position!(reader, 8);
        assert_buffer_position!(reader, 12);

        assert_next_data!(reader, "next");
        assert_position!(reader, 12);
        assert_buffer_position!(reader, 12);
    }

    mock_server("8887", responses, &mut check);
}
<commit_msg>update macro indentation<commit_after>extern crate file_api;
extern crate futures;
extern crate hyper;

use std::thread;
use std::io::Read;
use std::io::Write;
use std::io::SeekFrom;
use std::net::TcpListener;
use std::time::Duration;

use futures::channel::mpsc;

use file_api::http_reader::HttpReader;
use file_api::reader::Reader;

fn mock_server(port: &str, messages: Vec<String>, tester: &mut FnMut()) {
    let mut responses = messages.clone();
    responses.reverse();

    let address = ["127.0.0.1:", port].join("");
    let server = TcpListener::bind(address).unwrap();

    let (mut tx, _rx) = mpsc::channel(messages.len());
    let handler = thread::spawn(move || {
        while responses.len() != 0 {
            match responses.pop() {
                Some(response) => {
                    let mut inc = server.accept().unwrap().0;
                    inc.set_read_timeout(Some(Duration::from_secs(5))).unwrap();
                    inc.set_write_timeout(Some(Duration::from_secs(5))).unwrap();

                    let mut message = "".to_string();
                    let _result = inc.read_to_string(&mut message);
                    // println!("{:?} ==> {:?}", message, response);

                    if message != "" {
                        inc.write_all(response.as_ref()).unwrap();
                        let _ = tx.start_send(());
                    }
                }
                None => {}
            }
        }
    });

    tester();
    handler.join().unwrap();
}

macro_rules! assert_position {
    ($reader: expr, $position: expr) => {
        let position = $reader.get_position().unwrap();
        assert_eq!(position, $position);
    };
}

macro_rules! assert_buffer_position {
    ($reader: expr, $position: expr) => {
        assert_eq!($reader.buffer.position, $position);
    };
}

macro_rules! assert_next_data {
    ($reader:expr, $string_data:expr) => {
        let length = $string_data.len();
        let data = $reader.read(length).unwrap();
        assert_eq!(data.len(), length);
        let data_str = std::str::from_utf8(&data).unwrap();
        assert!(data_str == $string_data);
    };
}

#[test]
fn http_exists() {
    let responses = vec!["HTTP/1.1 200 OK\n\n".to_string()];

    fn check() {
        let file = "http://127.0.0.1:8880".to_string();
        assert!(file_api::exists(&file) == true);
    }

    mock_server("8880", responses, &mut check);
}

#[test]
fn http_not_exists() {
    let responses = vec!["HTTP/1.1 404 OK\n\n".to_string()];

    fn check() {
        let file = "http://127.0.0.1:8881".to_string();
        assert!(file_api::exists(&file) == false);
    }

    mock_server("8881", responses, &mut check);
}

#[test]
fn http_size() {
    let responses = vec!["HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string()];

    fn check() {
        let filename = "http://127.0.0.1:8882".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        let size = reader.get_size().unwrap();
        assert_eq!(size, 19);
    }

    mock_server("8882", responses, &mut check);
}

#[test]
fn http_read_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Range: bytes 0-3/19\r\n\r\nsome"
            .to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 4\r\nContent-Range: bytes 4-7/19\r\n\r\ndata"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8883/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        assert_position!(reader, 0);
        assert_next_data!(reader, "some".to_string());
        assert_position!(reader, 4);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
    }

    mock_server("8883", responses, &mut check);
}

#[test]
fn http_read_buffered_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 12\r\nContent-Range: bytes 0-11/19\r\n\r\nsomedatanext"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8884/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        reader.set_cache_size(Some(12));

        assert_position!(reader, 0);
        assert_buffer_position!(reader, 0);
        assert_next_data!(reader, "some".to_string());
        assert_position!(reader, 4);
        assert_buffer_position!(reader, 12);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
        assert_buffer_position!(reader, 12);

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(10));

        assert_position!(reader, 10);
        assert_buffer_position!(reader, 12);

        assert_next_data!(reader, "xt".to_string());
        assert_position!(reader, 12);
        assert_buffer_position!(reader, 12);
    }

    mock_server("8884", responses, &mut check);
}

#[test]
fn http_read_and_seek_buffered_data() {
    let responses = vec![
        "HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string(),
        "HTTP/1.1 200 OK\r\nContent-Length: 8\r\nContent-Range: bytes 4-11/19\r\n\r\ndatanext"
            .to_string(),
    ];

    fn check() {
        let filename = "http://127.0.0.1:8885/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(2));

        reader.set_cache_size(Some(8));

        let new_position = reader.seek(SeekFrom::Current(2));
        assert_eq!(new_position, Ok(4));

        assert_position!(reader, 4);
        assert_next_data!(reader, "data".to_string());
        assert_position!(reader, 8);
        assert_next_data!(reader, "next".to_string());
        assert_position!(reader, 12);
    }

    mock_server("8885", responses, &mut check);
}

#[test]
fn http_seek() {
    let responses = vec!["HTTP/1.1 200 OK\r\nContent-Length: 19\r\n\r\n".to_string()];
    fn check() {
        let filename = "http://127.0.0.1:8886/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        assert_position!(reader, 0);
        let position = reader.seek(SeekFrom::Current(4)).unwrap();
        assert_eq!(position, 4);
        assert_position!(reader, 4);
    }

    mock_server("8886", responses, &mut check);
}

#[test]
fn http_read_and_return_different_buffer_size() {
    let responses = vec![
    "HTTP/1.1 200 OK\r\nContent-Length: 19000\r\n\r\n".to_string(),
    "HTTP/1.1 200 OK\r\nContent-Length: 12\r\nContent-Range: bytes 0-12/19000\r\n\r\nsomedatanext".to_string(),
  ];

    fn check() {
        let filename = "http://127.0.0.1:8887/data".to_string();
        let mut reader: HttpReader = Reader::open(&filename);

        reader.set_cache_size(Some(100));
        assert_next_data!(reader, "somedata");

        assert_position!(reader, 8);
        assert_buffer_position!(reader, 12);

        assert_next_data!(reader, "next");
        assert_position!(reader, 12);
        assert_buffer_position!(reader, 12);
    }

    mock_server("8887", responses, &mut check);
}
<|endoftext|>


<commit_before>pub fn clear_screen() {
    print!("\x1b[2J\n");
}

pub trait Drawable {
    fn should_draw(&self, x: isize, y: isize) -> bool;
    fn get_height(&self) -> isize;
    fn get_width(&self) -> isize;
}

pub fn draw<T: Drawable>(ref world: &T) {
    clear_screen();
    for y in 0..world.get_height() {
        print!("\n");
        for x in 0..world.get_width() {
            if world.should_draw(x,y) {
                print!("□");
            } else {
                print!(" ");
            }

        }
    }
    print!("\n");
}
<commit_msg>add nice border<commit_after>pub fn clear_screen() {
    print!("\x1b[2J\n");
}

pub trait Drawable {
    fn should_draw(&self, x: isize, y: isize) -> bool;
    fn get_height(&self) -> isize;
    fn get_width(&self) -> isize;
}

pub fn draw<T: Drawable>(ref world: &T) {
    clear_screen();
    for x in 0..world.get_width() + 2 {
        if x % 2 != 0 {
            print!(".");
        } else {
            print!(" ");
        }

    }
    for y in 0..world.get_height() {
        print!("\n.");

        for x in 0..world.get_width() {
            if world.should_draw(x,y) {
                print!("□");
            } else {
                print!(" ");
            }

        }
        print!(".");
    }
    print!("\n");
    for x in 0..world.get_width() + 2 {
        if x % 2 != 0 {
            print!(".");
        } else {
            print!(" ");
        }

    }
    print!("\n");

}
<|endoftext|>


<commit_before>extern crate sdl2;

use sdl2::audio::{AudioCallback, AudioSpecDesired};
use std::time::Duration;

struct SquareWave {
    phase_inc: f32,
    phase: f32,
    volume: f32
}

impl AudioCallback for SquareWave {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        // Generate a square wave
        for x in out.iter_mut() {
            *x = match self.phase {
                0.0...0.5 => self.volume,
                _ => -self.volume
            };
            self.phase = (self.phase + self.phase_inc) % 1.0;
        }
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let audio_subsystem = sdl_context.audio().unwrap();

    let desired_spec = AudioSpecDesired {
        freq: Some(44100),
        channels: Some(1),  // mono
        samples: None       // default sample size
    };

    let device = audio_subsystem.open_playback(None, &desired_spec, |spec| {
        // Show obtained AudioSpec
        println!("{:?}", spec);

        // initialize the audio callback
        SquareWave {
            phase_inc: 440.0 / spec.freq as f32,
            phase: 0.0,
            volume: 0.25
        }
    }).unwrap();

    // Start playback
    device.resume();

    // Play for 2 seconds
    std::thread::sleep(Duration::from_millis(2000));

    // Device is automatically closed when dropped
}
<commit_msg>Fix floating-point literal used in pattern in example (#705)<commit_after>extern crate sdl2;

use sdl2::audio::{AudioCallback, AudioSpecDesired};
use std::time::Duration;

struct SquareWave {
    phase_inc: f32,
    phase: f32,
    volume: f32
}

impl AudioCallback for SquareWave {
    type Channel = f32;

    fn callback(&mut self, out: &mut [f32]) {
        // Generate a square wave
        for x in out.iter_mut() {
            *x = if self.phase < 0.5 { self.volume } else { -self.volume };
            self.phase = (self.phase + self.phase_inc) % 1.0;
        }
    }
}

fn main() {
    let sdl_context = sdl2::init().unwrap();
    let audio_subsystem = sdl_context.audio().unwrap();

    let desired_spec = AudioSpecDesired {
        freq: Some(44100),
        channels: Some(1),  // mono
        samples: None       // default sample size
    };

    let device = audio_subsystem.open_playback(None, &desired_spec, |spec| {
        // Show obtained AudioSpec
        println!("{:?}", spec);

        // initialize the audio callback
        SquareWave {
            phase_inc: 440.0 / spec.freq as f32,
            phase: 0.0,
            volume: 0.25
        }
    }).unwrap();

    // Start playback
    device.resume();

    // Play for 2 seconds
    std::thread::sleep(Duration::from_millis(2000));

    // Device is automatically closed when dropped
}
<|endoftext|>


<commit_before>use regex::Regex;

use crate::data_types::SolrAlleleSummary;

use std::collections::HashMap;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::do_solr_request;

#[derive(Deserialize, Debug)]
struct SolrAlleleResponse {
    pub docs: Vec<SolrAlleleSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrAlleleResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrAlleleResponse,
}

lazy_static! {
    static ref CLEAN_RE: Regex = Regex::new(r#"([\+\-\&\\!\(\)"\~\*\?:])"#).unwrap();
}

// remove non-alphanumeric chars and then split on spaces
pub fn clean_words(q: &str) -> Vec<String> {
    let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
    let lower_q = substring(&q.to_lowercase(), 200);
    CLEAN_RE.replace_all(&lower_q, "\\$1")
       .split_whitespace().map(|s| s.to_owned()).collect()
}

fn make_allele_url(config: &ServerConfig, q: &str, query_field_names: &[&str])
                   -> Option<String>
{
    let joined_query_fields = query_field_names.join(",");
    let mut allele_url =
        format!("{}/alleles/select?wt=json&hl=on&hl.fl={}&q=",
                &config.solr_url,
                &joined_query_fields);

    let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
    let lower_q = substring(&q.to_lowercase(), 200);

    let mut clean_words: Vec<String> = clean_words(&lower_q);

    if clean_words.is_empty() {
        return None
    }

    if clean_words.iter().any(|s| s == "Δ" || s == "δ") {
        clean_words.push("delta".to_owned());
    }
    if clean_words.iter().any(|s| s == "delete" || s =="delta") {
        clean_words.push("deletion".to_owned());
    }

    let url_parts =
        itertools::iproduct!(query_field_names, clean_words)
        .map(|(field_name, query_word)| {
            let weight = if *field_name == "name" || *field_name == "allele_type" {
                2.0
            } else {
                if *field_name == "synonyms" || *field_name == "gene_name" {
                    1.0
                } else {
                    0.2
                }
            };

            format!("{}:({})^{}", field_name, query_word, weight)
        })
        .collect::<Vec<String>>();

    allele_url += &url_parts.join(" OR ");

    Some(allele_url)
}

fn matches_from_container(container: SolrAlleleResponseContainer) -> Vec<SolrAlleleSummary> {
    let mut response_container: SolrAlleleResponseContainer = container;
    let mut hl_by_id = response_container.highlighting;
    let matches: Vec<SolrAlleleSummary> = response_container.response.docs
        .drain(0..)
        .map(|mut doc: SolrAlleleSummary| {
            doc.highlighting = hl_by_id.remove(doc.id.as_str())
                .unwrap_or_else(HashMap::new);
            doc
        }).collect();
    matches
}

pub fn search_alleles(config: &ServerConfig, q: &str) -> Result<Vec<SolrAlleleSummary>, String> {
    let query_field_names = ["name", "synonyms", "description", "allele_type",
                             "gene_name", "gene_uniquename"];
    let maybe_url = make_allele_url(config, q, &query_field_names);

    if let Some(url) = maybe_url {
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => Ok(matches_from_container(container)),
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<commit_msg>Make allele lookup prefer more exact matches<commit_after>use regex::Regex;

use crate::data_types::SolrAlleleSummary;

use std::collections::HashMap;

use crate::web::config::ServerConfig;
use crate::api::search_types::*;
use crate::api::search_utils::do_solr_request;

#[derive(Deserialize, Debug)]
struct SolrAlleleResponse {
    pub docs: Vec<SolrAlleleSummary>,
}

#[derive(Deserialize, Debug)]
struct SolrAlleleResponseContainer {
    pub highlighting: HashMap<SolrMatchId, SolrMatchHighlight>,
    pub response: SolrAlleleResponse,
}

lazy_static! {
    static ref WT_RE: Regex = Regex::new(r#"(\+)(\s+|$)"#).unwrap();
    static ref CLEAN_RE: Regex = Regex::new(r#"([\+\-\&\\!\(\)"\~\*\?:])"#).unwrap();
    static ref DELTA_RE: Regex = Regex::new(r#"[Δδ]"#).unwrap();
}

// split on spaces and tidy search string
fn allele_words(q: &str) -> Vec<String> {
    let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
    let lc_substr = substring(&q.to_lowercase(), 200);
    let q = DELTA_RE.replace_all(&lc_substr, "delta").replace("wild type", "wild_type");
    let q = WT_RE.replace_all(&q, " wild_type ");

    q.split_whitespace().map(|s| s.to_owned()).collect()
}

fn make_allele_url(config: &ServerConfig, q: &str)
                   -> Option<String>
{
    let query_field_names = ["name", "synonyms", "description",
                             "gene_name", "gene_uniquename"];

    let joined_query_fields = query_field_names.join(",");
    let mut allele_url =
        format!("{}/alleles/select?wt=json&hl=on&hl.fl={}&q=",
                &config.solr_url,
                &joined_query_fields);

    let substring = |s: &str, len: usize| s.chars().take(len).collect::<String>();
    let lower_q = substring(&q.to_lowercase(), 100);

    let mut words: Vec<String> = allele_words(&lower_q);

    if words.is_empty() {
        return None
    }

    if words.iter().any(|s| s == "delete" || s =="delta" || s == "deletion") {
        words.push("deletion".to_owned());
        words.push("delta".to_owned());
    }

    let mut url_parts = vec![];
    let mut clean_words = vec![];

    for word in &words {
        clean_words.push(CLEAN_RE.replace_all(&word, "\\$1"));

        url_parts.push(format!("name:({})^5.0", word));
        url_parts.push(format!("synonyms:({})^4.0", word));
        url_parts.push(format!("allele_type:({})^4.0", word));
        url_parts.push(format!("gene_name:({})^3.0", word));
        url_parts.push(format!("gene_uniquename:({})^3.0", word));
    }

    for word in &clean_words {
        url_parts.push(format!("description:({})^1.0", word));
    }

    allele_url += &url_parts.join(" OR ");

    Some(allele_url)
}

fn matches_from_container(container: SolrAlleleResponseContainer) -> Vec<SolrAlleleSummary> {
    let mut response_container: SolrAlleleResponseContainer = container;
    let mut hl_by_id = response_container.highlighting;
    let matches: Vec<SolrAlleleSummary> = response_container.response.docs
        .drain(0..)
        .map(|mut doc: SolrAlleleSummary| {
            doc.highlighting = hl_by_id.remove(doc.id.as_str())
                .unwrap_or_else(HashMap::new);
            doc
        }).collect();
    matches
}

pub fn search_alleles(config: &ServerConfig, q: &str) -> Result<Vec<SolrAlleleSummary>, String> {
    let maybe_url = make_allele_url(config, q);

    if let Some(url) = maybe_url {
        let res = do_solr_request(&url)?;

        match serde_json::from_reader(res) {
            Ok(container) => Ok(matches_from_container(container)),
            Err(err) => {
                Err(format!("Error parsing response from Solr: {:?}", err))
            }
        }
    } else {
        Ok(vec![])
    }
}
<|endoftext|>