<commit_before>type filename = str;

type file_pos = {ch: uint, byte: uint};

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */

enum file_substr {
    fss_none,
    fss_internal(span),
    fss_external({filename: str, line: uint, col: uint})
}

type filemap =
    @{name: filename, substr: file_substr, src: @str,
      start_pos: file_pos, mut lines: [file_pos]};

type codemap = @{mut files: [filemap]};

type loc = {file: filemap, line: uint, col: uint};

fn new_codemap() -> codemap { @{mut files: [] } }

fn new_filemap_w_substr(filename: filename, substr: file_substr,
                        src: @str,
                        start_pos_ch: uint, start_pos_byte: uint)
   -> filemap {
    ret @{name: filename, substr: substr, src: src,
          start_pos: {ch: start_pos_ch, byte: start_pos_byte},
          mut lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
}

fn new_filemap(filename: filename, src: @str,
               start_pos_ch: uint, start_pos_byte: uint)
    -> filemap {
    ret new_filemap_w_substr(filename, fss_none, src,
                             start_pos_ch, start_pos_byte);
}

fn mk_substr_filename(cm: codemap, sp: span) -> str
{
    let pos = lookup_char_pos(cm, sp.lo);
    ret #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
}

fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
    file.lines += [{ch: chpos, byte: byte_pos + file.start_pos.byte}];
}

type lookup_fn = fn@(file_pos) -> uint;

fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
    -> {fm: filemap, line: uint}
{
    let len = vec::len(map.files);
    let mut a = 0u;
    let mut b = len;
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    if (a >= len) {
        fail #fmt("position %u does not resolve to a source location", pos)
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    ret {fm: f, line: a};
}

fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
    let {fm: f, line: a} = lookup_line(map, pos, lookup);
    ret {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.byte; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_char_pos_adj(map: codemap, pos: uint)
    -> {filename: str, line: uint, col: uint, file: option<filemap>}
{
    let loc = lookup_char_pos(map, pos);
    alt (loc.file.substr) {
      fss_none {
        {filename: loc.file.name, line: loc.line, col: loc.col,
         file: some(loc.file)}
      }
      fss_internal(sp) {
        lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
      }
      fss_external(eloc) {
        {filename: eloc.filename,
         line: eloc.line + loc.line - 1u,
         col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
         file: none}
      }
    }
}

fn adjust_span(map: codemap, sp: span) -> span {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    let line = lookup_line(map, sp.lo, lookup);
    alt (line.fm.substr) {
      fss_none {sp}
      fss_internal(s) {
        adjust_span(map, {lo: s.lo + (sp.lo - line.fm.start_pos.ch),
                          hi: s.lo + (sp.hi - line.fm.start_pos.ch),
                          expn_info: sp.expn_info})}
      fss_external(_) {sp}
    }
}

enum expn_info_ {
    expanded_from({call_site: span,
                   callie: {name: str, span: option<span>}})
}
type expn_info = option<@expn_info_>;
type span = {lo: uint, hi: uint, expn_info: expn_info};

fn span_to_str_no_adj(sp: span, cm: codemap) -> str {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u: %u:%u", lo.file.name,
             lo.line, lo.col, hi.line, hi.col)
}

fn span_to_str(sp: span, cm: codemap) -> str {
    let lo = lookup_char_pos_adj(cm, sp.lo);
    let hi = lookup_char_pos_adj(cm, sp.hi);
    ret #fmt("%s:%u:%u: %u:%u", lo.filename,
             lo.line, lo.col, hi.line, hi.col)
}

type file_lines = {file: filemap, lines: [uint]};

fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let mut lines = [];
    uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; };
    ret @{file: lo.file, lines: lines};
}

fn get_line(fm: filemap, line: int) -> str unsafe {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end = alt str::find_char_from(*fm.src, '\n', begin) {
      some(e) { e }
      none { str::len(*fm.src) }
    };
    str::slice(*fm.src, begin, end)
}

fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
    -> {fm: filemap, pos: uint} {
    let {fm, line} = lookup_line(cm, chpos, {|pos| pos.ch});
    let line_offset = fm.lines[line].byte - fm.start_pos.byte;
    let col = chpos - fm.lines[line].ch;
    let col_offset = str::count_bytes(*fm.src, line_offset, col);
    {fm: fm, pos: line_offset + col_offset}
}

fn span_to_snippet(sp: span, cm: codemap::codemap) -> str {
    let begin = lookup_byte_offset(cm, sp.lo);
    let end = lookup_byte_offset(cm, sp.hi);
    assert begin.fm == end.fm;
    ret str::slice(*begin.fm.src, begin.pos, end.pos);
}

fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> str
{
    let fm = cm.files[fidx];
    ret str::slice(*fm.src, lo, hi)
}

fn get_filemap(cm: codemap, filename: str) -> filemap {
    for cm.files.each {|fm| if fm.name == filename { ret fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<commit_msg>syntax: Limit exports in codemap<commit_after>export filename;
export filemap;
export span;
export file_substr;
export codemap;
export expn_info;
export expn_info_;
export expanded_from;
export new_filemap;
export new_filemap_w_substr;
export mk_substr_filename;
export lookup_char_pos;
export adjust_span;
export span_to_str;
export span_to_lines;
export file_lines;
export get_line;
export next_line;
export span_to_snippet;
export loc;
export get_filemap;
export new_codemap;

type filename = str;

type file_pos = {ch: uint, byte: uint};

/* A codemap is a thing that maps uints to file/line/column positions
 * in a crate. This to make it possible to represent the positions
 * with single-word things, rather than passing records all over the
 * compiler.
 */

enum file_substr {
    fss_none,
    fss_internal(span),
    fss_external({filename: str, line: uint, col: uint})
}

type filemap =
    @{name: filename, substr: file_substr, src: @str,
      start_pos: file_pos, mut lines: [file_pos]};

type codemap = @{mut files: [filemap]};

type loc = {file: filemap, line: uint, col: uint};

fn new_codemap() -> codemap { @{mut files: [] } }

fn new_filemap_w_substr(filename: filename, substr: file_substr,
                        src: @str,
                        start_pos_ch: uint, start_pos_byte: uint)
   -> filemap {
    ret @{name: filename, substr: substr, src: src,
          start_pos: {ch: start_pos_ch, byte: start_pos_byte},
          mut lines: [{ch: start_pos_ch, byte: start_pos_byte}]};
}

fn new_filemap(filename: filename, src: @str,
               start_pos_ch: uint, start_pos_byte: uint)
    -> filemap {
    ret new_filemap_w_substr(filename, fss_none, src,
                             start_pos_ch, start_pos_byte);
}

fn mk_substr_filename(cm: codemap, sp: span) -> str
{
    let pos = lookup_char_pos(cm, sp.lo);
    ret #fmt("<%s:%u:%u>", pos.file.name, pos.line, pos.col);
}

fn next_line(file: filemap, chpos: uint, byte_pos: uint) {
    file.lines += [{ch: chpos, byte: byte_pos + file.start_pos.byte}];
}

type lookup_fn = fn@(file_pos) -> uint;

fn lookup_line(map: codemap, pos: uint, lookup: lookup_fn)
    -> {fm: filemap, line: uint}
{
    let len = vec::len(map.files);
    let mut a = 0u;
    let mut b = len;
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(map.files[m].start_pos) > pos { b = m; } else { a = m; }
    }
    if (a >= len) {
        fail #fmt("position %u does not resolve to a source location", pos)
    }
    let f = map.files[a];
    a = 0u;
    b = vec::len(f.lines);
    while b - a > 1u {
        let m = (a + b) / 2u;
        if lookup(f.lines[m]) > pos { b = m; } else { a = m; }
    }
    ret {fm: f, line: a};
}

fn lookup_pos(map: codemap, pos: uint, lookup: lookup_fn) -> loc {
    let {fm: f, line: a} = lookup_line(map, pos, lookup);
    ret {file: f, line: a + 1u, col: pos - lookup(f.lines[a])};
}

fn lookup_char_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_byte_pos(map: codemap, pos: uint) -> loc {
    fn lookup(pos: file_pos) -> uint { ret pos.byte; }
    ret lookup_pos(map, pos, lookup);
}

fn lookup_char_pos_adj(map: codemap, pos: uint)
    -> {filename: str, line: uint, col: uint, file: option<filemap>}
{
    let loc = lookup_char_pos(map, pos);
    alt (loc.file.substr) {
      fss_none {
        {filename: loc.file.name, line: loc.line, col: loc.col,
         file: some(loc.file)}
      }
      fss_internal(sp) {
        lookup_char_pos_adj(map, sp.lo + (pos - loc.file.start_pos.ch))
      }
      fss_external(eloc) {
        {filename: eloc.filename,
         line: eloc.line + loc.line - 1u,
         col: if loc.line == 1u {eloc.col + loc.col} else {loc.col},
         file: none}
      }
    }
}

fn adjust_span(map: codemap, sp: span) -> span {
    fn lookup(pos: file_pos) -> uint { ret pos.ch; }
    let line = lookup_line(map, sp.lo, lookup);
    alt (line.fm.substr) {
      fss_none {sp}
      fss_internal(s) {
        adjust_span(map, {lo: s.lo + (sp.lo - line.fm.start_pos.ch),
                          hi: s.lo + (sp.hi - line.fm.start_pos.ch),
                          expn_info: sp.expn_info})}
      fss_external(_) {sp}
    }
}

enum expn_info_ {
    expanded_from({call_site: span,
                   callie: {name: str, span: option<span>}})
}
type expn_info = option<@expn_info_>;
type span = {lo: uint, hi: uint, expn_info: expn_info};

fn span_to_str_no_adj(sp: span, cm: codemap) -> str {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    ret #fmt("%s:%u:%u: %u:%u", lo.file.name,
             lo.line, lo.col, hi.line, hi.col)
}

fn span_to_str(sp: span, cm: codemap) -> str {
    let lo = lookup_char_pos_adj(cm, sp.lo);
    let hi = lookup_char_pos_adj(cm, sp.hi);
    ret #fmt("%s:%u:%u: %u:%u", lo.filename,
             lo.line, lo.col, hi.line, hi.col)
}

type file_lines = {file: filemap, lines: [uint]};

fn span_to_lines(sp: span, cm: codemap::codemap) -> @file_lines {
    let lo = lookup_char_pos(cm, sp.lo);
    let hi = lookup_char_pos(cm, sp.hi);
    let mut lines = [];
    uint::range(lo.line - 1u, hi.line as uint) {|i| lines += [i]; };
    ret @{file: lo.file, lines: lines};
}

fn get_line(fm: filemap, line: int) -> str unsafe {
    let begin: uint = fm.lines[line].byte - fm.start_pos.byte;
    let end = alt str::find_char_from(*fm.src, '\n', begin) {
      some(e) { e }
      none { str::len(*fm.src) }
    };
    str::slice(*fm.src, begin, end)
}

fn lookup_byte_offset(cm: codemap::codemap, chpos: uint)
    -> {fm: filemap, pos: uint} {
    let {fm, line} = lookup_line(cm, chpos, {|pos| pos.ch});
    let line_offset = fm.lines[line].byte - fm.start_pos.byte;
    let col = chpos - fm.lines[line].ch;
    let col_offset = str::count_bytes(*fm.src, line_offset, col);
    {fm: fm, pos: line_offset + col_offset}
}

fn span_to_snippet(sp: span, cm: codemap::codemap) -> str {
    let begin = lookup_byte_offset(cm, sp.lo);
    let end = lookup_byte_offset(cm, sp.hi);
    assert begin.fm == end.fm;
    ret str::slice(*begin.fm.src, begin.pos, end.pos);
}

fn get_snippet(cm: codemap::codemap, fidx: uint, lo: uint, hi: uint) -> str
{
    let fm = cm.files[fidx];
    ret str::slice(*fm.src, lo, hi)
}

fn get_filemap(cm: codemap, filename: str) -> filemap {
    for cm.files.each {|fm| if fm.name == filename { ret fm; } }
    //XXjdm the following triggers a mismatched type bug
    //      (or expected function, found _|_)
    fail; // ("asking for " + filename + " which we don't know about");
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
//
<|endoftext|>


<commit_before>use std::io::Cursor;

use decoder::FarbfeldDecoder;
use encoder::FarbfeldEncoder;

#[test]
fn decode() {
    let buf = Cursor::new(IMAGE_DATA);
    let mut img = FarbfeldDecoder::new(buf).unwrap();
    let (w, h) = img.dimensions();
    let data = img.read_image().unwrap();
    assert_eq!(w, 3);
    assert_eq!(h, 3);
    assert_eq!(data, &IMAGE_DATA[::HEADER_LEN as usize..])
}

#[test]
fn encode() {
    let mut buf: Vec<u8>= Vec::new();
    if let Err(e) = FarbfeldEncoder(&mut buf).encode(3, 3, &IMAGE_DATA[::HEADER_LEN as usize..]) {
        panic!(e)
    }
    assert_eq!(&buf[..], IMAGE_DATA)
}

pub const IMAGE_DATA: &'static [u8] =
    b"farbfeld\
      \x00\x00\x00\x03\
      \x00\x00\x00\x03\
      \xff\x00\x00\xff\x00\xff\x00\xff\x00\x00\xff\xff\
      \x00\x00\xff\xff\x80\x80\x80\x80\x00\xff\x00\xff\
      \x00\xff\x00\xff\x00\x00\xff\xff\xff\x00\x00\xff";
<commit_msg>change test date to RGBA64<commit_after>use std::io::Cursor;

use decoder::FarbfeldDecoder;
use encoder::FarbfeldEncoder;

#[test]
fn decode() {
    let buf = Cursor::new(IMAGE_DATA);
    let mut img = FarbfeldDecoder::new(buf).unwrap();
    let (w, h) = img.dimensions();
    let data = img.read_image().unwrap();
    assert_eq!(w, 3);
    assert_eq!(h, 3);
    assert_eq!(data, &IMAGE_DATA[::HEADER_LEN as usize..])
}

#[test]
fn encode() {
    let mut buf: Vec<u8>= Vec::new();
    if let Err(e) = FarbfeldEncoder(&mut buf).encode(3, 3, &IMAGE_DATA[::HEADER_LEN as usize..]) {
        panic!(e)
    }
    assert_eq!(&buf[..], IMAGE_DATA)
}

pub const IMAGE_DATA: &'static [u8] =
    b"farbfeld\
      \x00\x00\x00\x03\
      \x00\x00\x00\x03\
      \xff\xff\x00\x00\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\
      \x00\x00\x00\x00\xff\xff\xff\xff\x80\x00\x80\x00\x80\x00\x80\x00\x00\x00\xff\xff\x00\x00\xff\xff\
      \x00\x00\xff\xff\x00\x00\xff\xff\x00\x00\x00\x00\xff\xff\xff\xff\xff\xff\x00\x00\x00\x00\xff\xff";
<|endoftext|>


<commit_before>use super::num::Checked;

macro_rules! test_unop {
    ($name:ident $t:ty: $op:tt $expr1:tt == $expr2:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            assert_eq!($op x, y);
        }
    };
}

macro_rules! test_binop {
    ($name:ident $t:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            let z = Checked::<$t>::from($expr3);
            let w = $expr2 as $t;
            assert_eq!(x $op y, z);
            assert_eq!(x $op w, z);
        }
    };
}

test_binop! (add1 u8: 5 + 6 == 11);
test_binop! (add2 u32: 3_000_000_000 + 2_000_000_000 == None);
test_binop! (add3 i32: (-2_000_000_000) + (-2_000_000_000) == None);
test_binop! (sub u8: 5 - 6 == None);
test_binop! (mul u8: 5 * 6 == 30);
test_binop! (mul2 i32: 2_000_000_000 * 3 == None);
test_binop! (div1 u8: 10 / 3 == 3);
test_binop! (div2 u8: 10 / 0 == None);
test_binop! (and u8: 5 & 6 == 4);
test_binop! (xor u8: 5 ^ 6 == 3);
test_binop! (or u8: 5 | 6 == 7);
test_binop! (rem u8: 10 % 3 == 1);
test_binop! (shl u32: 10 << 3 == 80);
test_binop! (shr u32: 80 >> 3 == 10);
test_unop! (neg1 u8: - 5 == None);
test_unop! (neg2 i8: - 5 == (-5));
test_unop! (not i8: ! 5 == (-6));
<commit_msg>change import of Checked<commit_after>use super::Checked;

macro_rules! test_unop {
    ($name:ident $t:ty: $op:tt $expr1:tt == $expr2:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            assert_eq!($op x, y);
        }
    };
}

macro_rules! test_binop {
    ($name:ident $t:ty: $expr1:tt $op:tt $expr2:tt == $expr3:tt) => {
        #[test]
        fn $name() {
            let x = Checked::<$t>::from($expr1);
            let y = Checked::<$t>::from($expr2);
            let z = Checked::<$t>::from($expr3);
            let w = $expr2 as $t;
            assert_eq!(x $op y, z);
            assert_eq!(x $op w, z);
        }
    };
}

test_binop! (add1 u8: 5 + 6 == 11);
test_binop! (add2 u32: 3_000_000_000 + 2_000_000_000 == None);
test_binop! (add3 i32: (-2_000_000_000) + (-2_000_000_000) == None);
test_binop! (sub u8: 5 - 6 == None);
test_binop! (mul u8: 5 * 6 == 30);
test_binop! (mul2 i32: 2_000_000_000 * 3 == None);
test_binop! (div1 u8: 10 / 3 == 3);
test_binop! (div2 u8: 10 / 0 == None);
test_binop! (and u8: 5 & 6 == 4);
test_binop! (xor u8: 5 ^ 6 == 3);
test_binop! (or u8: 5 | 6 == 7);
test_binop! (rem u8: 10 % 3 == 1);
test_binop! (shl u32: 10 << 3 == 80);
test_binop! (shr u32: 80 >> 3 == 10);
test_unop! (neg1 u8: - 5 == None);
test_unop! (neg2 i8: - 5 == (-5));
test_unop! (not i8: ! 5 == (-6));
<|endoftext|>


<commit_before>use std::thread;
use std::sync::mpsc;
/*
pub struct Timer {
    duration: usize,
    control_channel: mpsc::SyncSender(Option<()>),
}

impl Timer {
    pub fn new(duration_ms: usize, out_channel: mpsc::SyncSender<()>) -> Timer {
        Timer{
            duration: duration_ms,
            guard: thread::(|duration| {

            })
        }
    }
}
*/
<commit_msg>timer: implement Timer<commit_after>use std::thread;
use std::sync::mpsc;

pub struct Timer;

impl Timer {
    pub fn from_chan(ms: u32, tx: mpsc::SyncSender<()>) {
        thread::spawn(move || {
            loop {
                thread::sleep_ms(ms);
                if tx.send(()).is_err() {
                    break;
                }
            }
        });
    }
}
<|endoftext|>


<commit_before>use crate::errors;
#[cfg(feature = "std")]
use core::fmt::{self, Display};
use core::{iter::FromIterator, result};

#[cfg(feature = "std")]
use std::{convert::{TryFrom, TryInto}, time::{Duration, SystemTime, UNIX_EPOCH}};

use crate::alloc::{string::{ String, ToString }, vec::Vec};

/// A time tag in OSC message consists of two 32-bit integers where the first one denotes the number of seconds since 1900-01-01 and the second the fractions of a second.
/// For details on its semantics see http://opensoundcontrol.org/node/3/#timetags
///
/// # Examples
///
/// ```
/// #[cfg(feature = "std")]
/// {
///     use rosc::OscTime;
///     use std::{convert::TryFrom, time::UNIX_EPOCH};
///
///     assert_eq!(
///         OscTime::try_from(UNIX_EPOCH).unwrap(),
///         OscTime::from((2_208_988_800, 0))
///     );
/// }
/// ```
///
/// # Conversions between `(u32, u32)`
///
/// Prior to version `0.5.0` of this crate, `OscTime` was defined as a type alias to `(u32, u32)`.
/// If you are upgrading from one of these older versions, you can use [`.into()`](Into::into) to
/// convert between `(u32, u32)` and `OscTime` in either direction.
///
/// # Conversions between [`std::time::SystemTime`]
///
/// The traits in `std::convert` are implemented for converting between
/// [`SystemTime`](std::time::SystemTime) and `OscTime` in both directions. An `OscTime` can be
/// converted into a `SystemTime` using [`From`](std::convert::From)/[`Into`](std::convert::Into).
/// A `SystemTime` can be converted into an `OscTime` using
/// [`TryFrom`](std::convert::TryFrom)/[`TryInto`](std::convert::TryInto). The fallible variants of
/// the conversion traits are used this case because not every `SystemTime` can be represented as
/// an `OscTime`.
///
/// **These conversions are lossy**, but are tested to have a deviation within
/// 5 nanoseconds when converted back and forth in either direction.
///
/// Although any time since the OSC epoch (`1900-01-01 00:00:00 UTC`) can be represented using the
/// OSC timestamp format, this crate only allows conversions between times greater than or equal to
/// the [`UNIX_EPOCH`](std::time::UNIX_EPOCH). This allows the math used in the conversions to work
/// on 32-bit systems which cannot represent times that far back.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OscTime {
    pub seconds: u32,
    pub fractional: u32,
}

#[cfg(feature = "std")]
impl OscTime {
    const UNIX_OFFSET: u64 = 2_208_988_800; // From RFC 5905
    const TWO_POW_32: f64 = (u32::MAX as f64) + 1.0; // Number of bits in a `u32`
    const ONE_OVER_TWO_POW_32: f64 = 1.0 / OscTime::TWO_POW_32;
    const NANOS_PER_SECOND: f64 = 1.0e9;
    const SECONDS_PER_NANO: f64 = 1.0 / OscTime::NANOS_PER_SECOND;
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscTime {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> core::result::Result<OscTime, OscTimeError> {
        let duration_since_epoch = time
            .duration_since(UNIX_EPOCH)
            .map_err(|_| OscTimeError(OscTimeErrorKind::BeforeEpoch))?
            + Duration::new(OscTime::UNIX_OFFSET, 0);
        let seconds = u32::try_from(duration_since_epoch.as_secs())
            .map_err(|_| OscTimeError(OscTimeErrorKind::Overflow))?;
        let nanos = duration_since_epoch.subsec_nanos() as f64;
        let fractional = (nanos * OscTime::SECONDS_PER_NANO * OscTime::TWO_POW_32).round() as u32;
        Ok(OscTime {
            seconds,
            fractional,
        })
    }
}

#[cfg(feature = "std")]
impl From<OscTime> for SystemTime {
    fn from(time: OscTime) -> SystemTime {
        let nanos =
            (time.fractional as f64) * OscTime::ONE_OVER_TWO_POW_32 * OscTime::NANOS_PER_SECOND;
        let duration_since_osc_epoch = Duration::new(time.seconds as u64, nanos as u32);
        let duration_since_unix_epoch =
            duration_since_osc_epoch - Duration::new(OscTime::UNIX_OFFSET, 0);
        UNIX_EPOCH + duration_since_unix_epoch
    }
}

impl From<(u32, u32)> for OscTime {
    fn from(time: (u32, u32)) -> OscTime {
        let (seconds, fractional) = time;
        OscTime {
            seconds,
            fractional,
        }
    }
}

impl From<OscTime> for (u32, u32) {
    fn from(time: OscTime) -> (u32, u32) {
        (time.seconds, time.fractional)
    }
}

#[cfg(feature = "std")]
/// An error returned by conversions involving [`OscTime`].
#[derive(Debug)]
pub struct OscTimeError(OscTimeErrorKind);

#[cfg(feature = "std")]
#[derive(Debug)]
enum OscTimeErrorKind {
    BeforeEpoch,
    Overflow,
}

#[cfg(feature = "std")]
impl Display for OscTimeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            OscTimeErrorKind::BeforeEpoch => {
                write!(f, "time is before the unix epoch and cannot be stored")
            }
            OscTimeErrorKind::Overflow => {
                write!(f, "time overflows what OSC time can store")
            }
        }
    }
}

// impl error::Error for OscTimeError {}

/// see OSC Type Tag String: [OSC Spec. 1.0](http://opensoundcontrol.org/spec-1_0)
/// padding: zero bytes (n*4)
#[derive(Clone, Debug, PartialEq)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(OscTime),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Array(OscArray),
    Nil,
    Inf,
}
macro_rules! value_impl {
    ($(($name:ident, $variant:ident, $ty:ty)),*) => {
        $(
        impl OscType {
            #[allow(dead_code)]
            pub fn $name(self) -> Option<$ty> {
                match self {
                    OscType::$variant(v) => Some(v),
                    _ => None
                }
            }
        }
        impl From<$ty> for OscType {
            fn from(v: $ty) -> Self {
                OscType::$variant(v)
            }
        }
        )*
    }
}
value_impl! {
    (int, Int, i32),
    (float, Float, f32),
    (string, String, String),
    (blob, Blob, Vec<u8>),
    (array, Array, OscArray),
    (long, Long, i64),
    (double, Double, f64),
    (char, Char, char),
    (color, Color, OscColor),
    (midi, Midi, OscMidiMessage),
    (bool, Bool, bool)
}
impl From<(u32, u32)> for OscType {
    fn from(time: (u32, u32)) -> Self {
        OscType::Time(time.into())
    }
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscType {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> std::result::Result<OscType, OscTimeError> {
        time.try_into().map(OscType::Time)
    }
}

impl OscType {
    pub fn time(self) -> Option<OscTime> {
        match self {
            OscType::Time(time) => Some(time),
            _ => None,
        }
    }
}
impl<'a> From<&'a str> for OscType {
    fn from(string: &'a str) -> Self {
        OscType::String(string.to_string())
    }
}
/// Represents the parts of a Midi message. Mainly used for
/// tunneling midi over a network using the OSC protocol.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

/// An OSC message consists of an address and
/// zero or more arguments. The address should
/// specify an element of your Instrument (or whatever
/// you want to control with OSC) and the arguments
/// are used to set properties of the element to the
/// respective values.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMessage {
    pub addr: String,
    pub args: Vec<OscType>,
}

/// An OSC bundle contains zero or more OSC packets
/// and a time tag. The contained packets *should* be
/// applied at the given time tag.
#[derive(Clone, Debug, PartialEq)]
pub struct OscBundle {
    pub timetag: OscTime,
    pub content: Vec<OscPacket>,
}

/// An RGBA color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

/// An OscArray color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscArray {
    pub content: Vec<OscType>,
}

impl<T: Into<OscType>> FromIterator<T> for OscArray {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> OscArray {
        OscArray {
            content: iter.into_iter().map(T::into).collect(),
        }
    }
}

pub type Result<T> = result::Result<T, errors::OscError>;

impl From<String> for OscMessage {
    fn from(s: String) -> OscMessage {
        OscMessage {
            addr: s,
            args: vec![],
        }
    }
}
impl<'a> From<&'a str> for OscMessage {
    fn from(s: &str) -> OscMessage {
        OscMessage {
            addr: s.to_string(),
            args: vec![],
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "std")]
    use super::*;
    #[cfg(feature = "std")]
    use std::time::UNIX_EPOCH;

    #[cfg(feature = "std")]
    const TOLERANCE_NANOS: u64 = 5;

    #[cfg(feature = "std")]
    #[test]
    fn system_times_can_be_converted_to_and_from_osc() {
        let times = vec![UNIX_EPOCH, SystemTime::now()];
        for time in times {
            for i in 0..1000 {
                let time = time + Duration::from_nanos(1) * i;
                assert_eq_system_times(time, SystemTime::from(OscTime::try_from(time).unwrap()));
            }
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_times_can_be_converted_to_and_from_system_times() {
        let mut times = vec![];
        // Sweep across a few numbers to check for tolerance
        for seconds in vec![
            // We don't start at zero because times before the UNIX_EPOCH cannot be converted to
            // OscTime.
            OscTime::UNIX_OFFSET as u32,
            OscTime::UNIX_OFFSET as u32 + 1,
            OscTime::UNIX_OFFSET as u32 + 2,
            OscTime::UNIX_OFFSET as u32 + 3,
            u32::MAX - 1,
            u32::MAX,
        ] {
            let fractional_max = 100;
            for fractional in 0..fractional_max {
                times.push((seconds, fractional));
                times.push((seconds, fractional_max - fractional));
            }
        }

        for osc_time in times.into_iter().map(OscTime::from) {
            assert_eq_osc_times(
                osc_time,
                OscTime::try_from(SystemTime::from(osc_time)).unwrap(),
            );
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_time_cannot_represent_times_before_1970_01_01() {
        assert!(OscTime::try_from(UNIX_EPOCH - Duration::from_secs(1)).is_err())
    }

    #[cfg(feature = "std")]
    fn assert_eq_system_times(a: SystemTime, b: SystemTime) {
        let difference = if a < b {
            b.duration_since(a).unwrap()
        } else {
            a.duration_since(b).unwrap()
        };

        let tolerance = Duration::from_nanos(TOLERANCE_NANOS);

        if difference > tolerance {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {:?}",
                a, b, tolerance,
            );
        }
    }

    #[cfg(feature = "std")]
    fn assert_eq_osc_times(a: OscTime, b: OscTime) {
        // I did not want to implement subtraction with carrying in order to implement this in the
        // same way as the alternative for system times. Intsead we are compare each part of the
        // OSC times separately.
        let tolerance_fractional_seconds = ((TOLERANCE_NANOS as f64 * OscTime::TWO_POW_32)
            / OscTime::NANOS_PER_SECOND)
            .round() as i64;
        assert_eq!(
            a.seconds, b.seconds,
            "the seconds components of {:?} and {:?} are different",
            a, b
        );
        if (a.fractional as i64 - b.fractional as i64).abs() > tolerance_fractional_seconds {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {} fractional seconds",
                a, b, tolerance_fractional_seconds,
            );
        }
    }
}
<commit_msg>OscTime -> SystemTime conversion: round nanos.<commit_after>use crate::errors;
#[cfg(feature = "std")]
use core::fmt::{self, Display};
use core::{iter::FromIterator, result};

#[cfg(feature = "std")]
use std::{convert::{TryFrom, TryInto}, time::{Duration, SystemTime, UNIX_EPOCH}};

use crate::alloc::{string::{ String, ToString }, vec::Vec};

/// A time tag in OSC message consists of two 32-bit integers where the first one denotes the number of seconds since 1900-01-01 and the second the fractions of a second.
/// For details on its semantics see http://opensoundcontrol.org/node/3/#timetags
///
/// # Examples
///
/// ```
/// #[cfg(feature = "std")]
/// {
///     use rosc::OscTime;
///     use std::{convert::TryFrom, time::UNIX_EPOCH};
///
///     assert_eq!(
///         OscTime::try_from(UNIX_EPOCH).unwrap(),
///         OscTime::from((2_208_988_800, 0))
///     );
/// }
/// ```
///
/// # Conversions between `(u32, u32)`
///
/// Prior to version `0.5.0` of this crate, `OscTime` was defined as a type alias to `(u32, u32)`.
/// If you are upgrading from one of these older versions, you can use [`.into()`](Into::into) to
/// convert between `(u32, u32)` and `OscTime` in either direction.
///
/// # Conversions between [`std::time::SystemTime`]
///
/// The traits in `std::convert` are implemented for converting between
/// [`SystemTime`](std::time::SystemTime) and `OscTime` in both directions. An `OscTime` can be
/// converted into a `SystemTime` using [`From`](std::convert::From)/[`Into`](std::convert::Into).
/// A `SystemTime` can be converted into an `OscTime` using
/// [`TryFrom`](std::convert::TryFrom)/[`TryInto`](std::convert::TryInto). The fallible variants of
/// the conversion traits are used this case because not every `SystemTime` can be represented as
/// an `OscTime`.
///
/// **These conversions are lossy**, but are tested to have a deviation within
/// 5 nanoseconds when converted back and forth in either direction.
///
/// Although any time since the OSC epoch (`1900-01-01 00:00:00 UTC`) can be represented using the
/// OSC timestamp format, this crate only allows conversions between times greater than or equal to
/// the [`UNIX_EPOCH`](std::time::UNIX_EPOCH). This allows the math used in the conversions to work
/// on 32-bit systems which cannot represent times that far back.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct OscTime {
    pub seconds: u32,
    pub fractional: u32,
}

#[cfg(feature = "std")]
impl OscTime {
    const UNIX_OFFSET: u64 = 2_208_988_800; // From RFC 5905
    const TWO_POW_32: f64 = (u32::MAX as f64) + 1.0; // Number of bits in a `u32`
    const ONE_OVER_TWO_POW_32: f64 = 1.0 / OscTime::TWO_POW_32;
    const NANOS_PER_SECOND: f64 = 1.0e9;
    const SECONDS_PER_NANO: f64 = 1.0 / OscTime::NANOS_PER_SECOND;
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscTime {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> core::result::Result<OscTime, OscTimeError> {
        let duration_since_epoch = time
            .duration_since(UNIX_EPOCH)
            .map_err(|_| OscTimeError(OscTimeErrorKind::BeforeEpoch))?
            + Duration::new(OscTime::UNIX_OFFSET, 0);
        let seconds = u32::try_from(duration_since_epoch.as_secs())
            .map_err(|_| OscTimeError(OscTimeErrorKind::Overflow))?;
        let nanos = duration_since_epoch.subsec_nanos() as f64;
        let fractional = (nanos * OscTime::SECONDS_PER_NANO * OscTime::TWO_POW_32).round() as u32;
        Ok(OscTime {
            seconds,
            fractional,
        })
    }
}

#[cfg(feature = "std")]
impl From<OscTime> for SystemTime {
    fn from(time: OscTime) -> SystemTime {
        let nanos =
            (time.fractional as f64) * OscTime::ONE_OVER_TWO_POW_32 * OscTime::NANOS_PER_SECOND;
        let duration_since_osc_epoch = Duration::new(time.seconds as u64, nanos.round() as u32);
        let duration_since_unix_epoch =
            duration_since_osc_epoch - Duration::new(OscTime::UNIX_OFFSET, 0);
        UNIX_EPOCH + duration_since_unix_epoch
    }
}

impl From<(u32, u32)> for OscTime {
    fn from(time: (u32, u32)) -> OscTime {
        let (seconds, fractional) = time;
        OscTime {
            seconds,
            fractional,
        }
    }
}

impl From<OscTime> for (u32, u32) {
    fn from(time: OscTime) -> (u32, u32) {
        (time.seconds, time.fractional)
    }
}

#[cfg(feature = "std")]
/// An error returned by conversions involving [`OscTime`].
#[derive(Debug)]
pub struct OscTimeError(OscTimeErrorKind);

#[cfg(feature = "std")]
#[derive(Debug)]
enum OscTimeErrorKind {
    BeforeEpoch,
    Overflow,
}

#[cfg(feature = "std")]
impl Display for OscTimeError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self.0 {
            OscTimeErrorKind::BeforeEpoch => {
                write!(f, "time is before the unix epoch and cannot be stored")
            }
            OscTimeErrorKind::Overflow => {
                write!(f, "time overflows what OSC time can store")
            }
        }
    }
}

// impl error::Error for OscTimeError {}

/// see OSC Type Tag String: [OSC Spec. 1.0](http://opensoundcontrol.org/spec-1_0)
/// padding: zero bytes (n*4)
#[derive(Clone, Debug, PartialEq)]
pub enum OscType {
    Int(i32),
    Float(f32),
    String(String),
    Blob(Vec<u8>),
    // use struct for time tag to avoid destructuring
    Time(OscTime),
    Long(i64),
    Double(f64),
    Char(char),
    Color(OscColor),
    Midi(OscMidiMessage),
    Bool(bool),
    Array(OscArray),
    Nil,
    Inf,
}
macro_rules! value_impl {
    ($(($name:ident, $variant:ident, $ty:ty)),*) => {
        $(
        impl OscType {
            #[allow(dead_code)]
            pub fn $name(self) -> Option<$ty> {
                match self {
                    OscType::$variant(v) => Some(v),
                    _ => None
                }
            }
        }
        impl From<$ty> for OscType {
            fn from(v: $ty) -> Self {
                OscType::$variant(v)
            }
        }
        )*
    }
}
value_impl! {
    (int, Int, i32),
    (float, Float, f32),
    (string, String, String),
    (blob, Blob, Vec<u8>),
    (array, Array, OscArray),
    (long, Long, i64),
    (double, Double, f64),
    (char, Char, char),
    (color, Color, OscColor),
    (midi, Midi, OscMidiMessage),
    (bool, Bool, bool)
}
impl From<(u32, u32)> for OscType {
    fn from(time: (u32, u32)) -> Self {
        OscType::Time(time.into())
    }
}

#[cfg(feature = "std")]
impl TryFrom<SystemTime> for OscType {
    type Error = OscTimeError;

    fn try_from(time: SystemTime) -> std::result::Result<OscType, OscTimeError> {
        time.try_into().map(OscType::Time)
    }
}

impl OscType {
    pub fn time(self) -> Option<OscTime> {
        match self {
            OscType::Time(time) => Some(time),
            _ => None,
        }
    }
}
impl<'a> From<&'a str> for OscType {
    fn from(string: &'a str) -> Self {
        OscType::String(string.to_string())
    }
}
/// Represents the parts of a Midi message. Mainly used for
/// tunneling midi over a network using the OSC protocol.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMidiMessage {
    pub port: u8,
    pub status: u8,
    pub data1: u8, // maybe use an enum for data?
    pub data2: u8,
}

/// An *osc packet* can contain an *osc message* or a bundle of nested messages
/// which is called *osc bundle*.
#[derive(Clone, Debug, PartialEq)]
pub enum OscPacket {
    Message(OscMessage),
    Bundle(OscBundle),
}

/// An OSC message consists of an address and
/// zero or more arguments. The address should
/// specify an element of your Instrument (or whatever
/// you want to control with OSC) and the arguments
/// are used to set properties of the element to the
/// respective values.
#[derive(Clone, Debug, PartialEq)]
pub struct OscMessage {
    pub addr: String,
    pub args: Vec<OscType>,
}

/// An OSC bundle contains zero or more OSC packets
/// and a time tag. The contained packets *should* be
/// applied at the given time tag.
#[derive(Clone, Debug, PartialEq)]
pub struct OscBundle {
    pub timetag: OscTime,
    pub content: Vec<OscPacket>,
}

/// An RGBA color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscColor {
    pub red: u8,
    pub green: u8,
    pub blue: u8,
    pub alpha: u8,
}

/// An OscArray color.
#[derive(Clone, Debug, PartialEq)]
pub struct OscArray {
    pub content: Vec<OscType>,
}

impl<T: Into<OscType>> FromIterator<T> for OscArray {
    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> OscArray {
        OscArray {
            content: iter.into_iter().map(T::into).collect(),
        }
    }
}

pub type Result<T> = result::Result<T, errors::OscError>;

impl From<String> for OscMessage {
    fn from(s: String) -> OscMessage {
        OscMessage {
            addr: s,
            args: vec![],
        }
    }
}
impl<'a> From<&'a str> for OscMessage {
    fn from(s: &str) -> OscMessage {
        OscMessage {
            addr: s.to_string(),
            args: vec![],
        }
    }
}

#[cfg(test)]
mod tests {
    #[cfg(feature = "std")]
    use super::*;
    #[cfg(feature = "std")]
    use std::time::UNIX_EPOCH;

    #[cfg(feature = "std")]
    const TOLERANCE_NANOS: u64 = 5;

    #[cfg(feature = "std")]
    #[test]
    fn system_times_can_be_converted_to_and_from_osc() {
        let times = vec![UNIX_EPOCH, SystemTime::now()];
        for time in times {
            for i in 0..1000 {
                let time = time + Duration::from_nanos(1) * i;
                assert_eq_system_times(time, SystemTime::from(OscTime::try_from(time).unwrap()));
            }
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_times_can_be_converted_to_and_from_system_times() {
        let mut times = vec![];
        // Sweep across a few numbers to check for tolerance
        for seconds in vec![
            // We don't start at zero because times before the UNIX_EPOCH cannot be converted to
            // OscTime.
            OscTime::UNIX_OFFSET as u32,
            OscTime::UNIX_OFFSET as u32 + 1,
            OscTime::UNIX_OFFSET as u32 + 2,
            OscTime::UNIX_OFFSET as u32 + 3,
            u32::MAX - 1,
            u32::MAX,
        ] {
            let fractional_max = 100;
            for fractional in 0..fractional_max {
                times.push((seconds, fractional));
                times.push((seconds, fractional_max - fractional));
            }
        }

        for osc_time in times.into_iter().map(OscTime::from) {
            assert_eq_osc_times(
                osc_time,
                OscTime::try_from(SystemTime::from(osc_time)).unwrap(),
            );
        }
    }

    #[cfg(feature = "std")]
    #[test]
    fn osc_time_cannot_represent_times_before_1970_01_01() {
        assert!(OscTime::try_from(UNIX_EPOCH - Duration::from_secs(1)).is_err())
    }

    #[cfg(feature = "std")]
    fn assert_eq_system_times(a: SystemTime, b: SystemTime) {
        let difference = if a < b {
            b.duration_since(a).unwrap()
        } else {
            a.duration_since(b).unwrap()
        };

        let tolerance = Duration::from_nanos(TOLERANCE_NANOS);

        if difference > tolerance {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {:?}",
                a, b, tolerance,
            );
        }
    }

    #[cfg(feature = "std")]
    fn assert_eq_osc_times(a: OscTime, b: OscTime) {
        // I did not want to implement subtraction with carrying in order to implement this in the
        // same way as the alternative for system times. Intsead we are compare each part of the
        // OSC times separately.
        let tolerance_fractional_seconds = ((TOLERANCE_NANOS as f64 * OscTime::TWO_POW_32)
            / OscTime::NANOS_PER_SECOND)
            .round() as i64;
        assert_eq!(
            a.seconds, b.seconds,
            "the seconds components of {:?} and {:?} are different",
            a, b
        );
        if (a.fractional as i64 - b.fractional as i64).abs() > tolerance_fractional_seconds {
            panic!(
                "the fractional seconds components of {:?} and {:?} vary more than the required tolerance of {} fractional seconds",
                a, b, tolerance_fractional_seconds,
            );
        }
    }
}
<|endoftext|>


<commit_before>//! Common types used across the crate.

pub use hyper::Method as RequestMethod;
pub use hyper::status::StatusCode;
pub use json::Map as JsonMap;
pub use json::Number as JsonNumber;
pub use json::Value as JsonValue;
pub use url::Url;

use bytes::Bytes;
use chrono::{DateTime as ChronoDateTime, UTC};
use std::ops::Deref;
use std::str::{self, Utf8Error};

string_enums! {
    /// Represents the `filter_level` field in Tweets or `filter_level` parameter in API request.
    #[derive(Clone, Debug)]
    pub enum FilterLevel {
        :None("none"),
        :Low("low"),
        :Medium("medium");
        :Custom(_),
    }

    /// A value for `with` parameter for User and Site Streams.
    #[derive(Clone, Debug)]
    pub enum With {
        /// Instruct the stream to send messages only from the user associated with that stream.
        /// The default for Site Streams.
        :User("user"),
        /// Instruct the stream to send messages from accounts the user follows as well, equivalent
        /// to the user’s home timeline. The default for User Streams.
        :Following("following");
        /// Custom value.
        :Custom(_),
    }

    /// Represents the `withheld_scope` field in `Tweet` and `User`.
    #[derive(Clone, Debug)]
    pub enum WithheldScope {
        :Status("status"),
        :User("user");
        :Custom(_),
    }
}

pub type DateTime = ChronoDateTime<UTC>;

/// A string type returned by `TwitterJsonStream`.
// It is basically a wrapper type over `Bytes` that gurantees the contained bytes are valid UTF8 string.
// Inspired by hyper::http::str::ByteStr.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug, Hash)]
pub struct JsonStr {
    inner: Bytes,
}

impl JsonStr {
    #[doc(hidden)]
    pub fn from_utf8(v: Bytes) -> Result<Self, Utf8Error> {
        str::from_utf8(&v)?;
        unsafe { Ok(JsonStr::from_utf8_unchecked(v)) }
    }

    pub fn from_static(s: &'static str) -> Self {
        JsonStr {
            inner: Bytes::from_static(s.as_ref()),
        }
    }

    #[doc(hidden)]
    pub unsafe fn from_utf8_unchecked(v: Bytes) -> Self {
        JsonStr {
            inner: v,
        }
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.inner) }
    }
}

impl AsRef<str> for JsonStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl Deref for JsonStr {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl From<String> for JsonStr {
    fn from(s: String) -> Self {
        JsonStr {
            inner: s.into_bytes().into(),
        }
    }
}

impl<'a> From<&'a str> for JsonStr {
    fn from(s: &'a str) -> Self {
        JsonStr {
            inner: s.into(),
        }
    }
}

impl From<JsonStr> for Bytes {
    fn from(s: JsonStr) -> Self {
        s.inner
    }
}

impl ::std::default::Default for FilterLevel {
    fn default() -> Self {
        FilterLevel::None
    }
}
<commit_msg>Implement `Display` for `JsonStr`<commit_after>//! Common types used across the crate.

pub use hyper::Method as RequestMethod;
pub use hyper::status::StatusCode;
pub use json::Map as JsonMap;
pub use json::Number as JsonNumber;
pub use json::Value as JsonValue;
pub use url::Url;

use bytes::Bytes;
use chrono::{DateTime as ChronoDateTime, UTC};
use std::fmt::{self, Display, Formatter};
use std::ops::Deref;
use std::str::{self, Utf8Error};

string_enums! {
    /// Represents the `filter_level` field in Tweets or `filter_level` parameter in API request.
    #[derive(Clone, Debug)]
    pub enum FilterLevel {
        :None("none"),
        :Low("low"),
        :Medium("medium");
        :Custom(_),
    }

    /// A value for `with` parameter for User and Site Streams.
    #[derive(Clone, Debug)]
    pub enum With {
        /// Instruct the stream to send messages only from the user associated with that stream.
        /// The default for Site Streams.
        :User("user"),
        /// Instruct the stream to send messages from accounts the user follows as well, equivalent
        /// to the user’s home timeline. The default for User Streams.
        :Following("following");
        /// Custom value.
        :Custom(_),
    }

    /// Represents the `withheld_scope` field in `Tweet` and `User`.
    #[derive(Clone, Debug)]
    pub enum WithheldScope {
        :Status("status"),
        :User("user");
        :Custom(_),
    }
}

pub type DateTime = ChronoDateTime<UTC>;

/// A string type returned by `TwitterJsonStream`.
// It is basically a wrapper type over `Bytes` that gurantees the contained bytes are valid UTF8 string.
// Inspired by hyper::http::str::ByteStr.
#[derive(Clone, PartialEq, PartialOrd, Ord, Eq, Debug, Hash)]
pub struct JsonStr {
    inner: Bytes,
}

impl JsonStr {
    #[doc(hidden)]
    pub fn from_utf8(v: Bytes) -> Result<Self, Utf8Error> {
        str::from_utf8(&v)?;
        unsafe { Ok(JsonStr::from_utf8_unchecked(v)) }
    }

    pub fn from_static(s: &'static str) -> Self {
        JsonStr {
            inner: Bytes::from_static(s.as_ref()),
        }
    }

    #[doc(hidden)]
    pub unsafe fn from_utf8_unchecked(v: Bytes) -> Self {
        JsonStr {
            inner: v,
        }
    }

    pub fn as_str(&self) -> &str {
        unsafe { str::from_utf8_unchecked(&self.inner) }
    }
}

impl AsRef<str> for JsonStr {
    fn as_ref(&self) -> &str {
        self.as_str()
    }
}

impl Deref for JsonStr {
    type Target = str;

    fn deref(&self) -> &str {
        self.as_str()
    }
}

impl Display for JsonStr {
    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
        self.as_str().fmt(f)
    }
}

impl From<String> for JsonStr {
    fn from(s: String) -> Self {
        JsonStr {
            inner: s.into_bytes().into(),
        }
    }
}

impl<'a> From<&'a str> for JsonStr {
    fn from(s: &'a str) -> Self {
        JsonStr {
            inner: s.into(),
        }
    }
}

impl From<JsonStr> for Bytes {
    fn from(s: JsonStr) -> Self {
        s.inner
    }
}

impl ::std::default::Default for FilterLevel {
    fn default() -> Self {
        FilterLevel::None
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::error::Error;
use std::path::PathBuf;
use std::io::prelude::*;
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response code).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, code: u16) -> Response {
    let mut res = Response::new();

    res.set_code(code);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 22] = [
            ("%20", " "),
            ("%3C", "<"),
            ("%3E", ">"),
            ("%23", "#"),
            ("%25", "%"),
            ("%7B", "["),
            ("%7D", ")"),
            ("%7C", "|"),
            ("%5C", "\\"),
            ("%5E", "^"),
            ("%7E", "~"),
            ("%5B", "["),
            ("%5D", ")"),
            ("%60", "`"),
            ("%3B", ";"),
            ("%2F", "/"),
            ("%3F", "?"),
            ("%3A", ":"),
            ("%40", "@"),
            ("%3D", "="),
            ("%26", "&"),
            ("%24", "$"),
    ];

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.set_code(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(e)  => {
                    return make_response(err_body("internal server error", e.description()), "text/html", 500);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}
<commit_msg>add three more error message handlers (403/404/500) for returning JSON instead of HTML<commit_after>// Copyright (c) 2016
// Jeff Nettleton
//
// Licensed under the MIT license (http://opensource.org/licenses/MIT). This
// file may not be copied, modified, or distributed except according to those
// terms

use std::env;
use std::fs::File;
use std::error::Error;
use std::path::PathBuf;
use std::io::prelude::*;
use response::{ToOutput, Response};
use request::Request;

/// Convenience method for creating a response from the basic components
/// required (a request body, content type, and response code).
///
/// # Examples
///
/// ```rust
/// use canteen::{Request, Response};
/// use canteen::utils;
///
/// fn handler(_: &Request) -> Response {
///     utils::make_response("Hello, world!", "text/plain", 200)
/// }
/// ```
pub fn make_response<T: ToOutput>(body: T, c_type: &str, code: u16) -> Response {
    let mut res = Response::new();

    res.set_code(code);
    res.set_content_type(c_type);
    res.append(body);

    res
}

/// Replace the URI escape codes with their ASCII equivalents.
pub fn replace_escape(path: &str) -> String {
    let mut fixed = String::from(path);
    let replaces: [(&str, &str); 22] = [
            ("%20", " "),
            ("%3C", "<"),
            ("%3E", ">"),
            ("%23", "#"),
            ("%25", "%"),
            ("%7B", "["),
            ("%7D", ")"),
            ("%7C", "|"),
            ("%5C", "\\"),
            ("%5E", "^"),
            ("%7E", "~"),
            ("%5B", "["),
            ("%5D", ")"),
            ("%60", "`"),
            ("%3B", ";"),
            ("%2F", "/"),
            ("%3F", "?"),
            ("%3A", ":"),
            ("%40", "@"),
            ("%3D", "="),
            ("%26", "&"),
            ("%24", "$"),
    ];

    for &(from, to) in replaces.iter() {
        fixed = fixed.replace(from, to);
    }

    fixed
}

fn err_body(message: &str, path: &str) -> String {
    format!("\
             \

Your request failed

{}: {}
", message, path)
}

/// Default handler function for HTTP 403 errors.
pub fn err_403(req: &Request) -> Response {
    make_response(err_body("forbidden", &req.path), "text/html", 403)
}

/// Default handler function for HTTP 403 errors for XHR.
pub fn err_403_json(message: &str) -> Response {
    make_response(format!("{{ message: 'forbidden: {}' }}", message), "application/json", 403)
}

/// Default handler function for HTTP 404 errors.
pub fn err_404(req: &Request) -> Response {
    make_response(err_body("not found", &req.path), "text/html", 404)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_404_json(message: &str) -> Response {
    make_response(format!("{{ message: 'not found: {}' }}", message), "application/json", 404)
}

/// Default handler function for HTTP 500 errors.
pub fn err_500(req: &Request) -> Response {
    make_response(err_body("internal server error", &req.path), "text/html", 500)
}

/// Default handler function for HTTP 500 errors for XHR.
pub fn err_500_json(message: &str) -> Response {
    make_response(format!("{{ message: 'internal server error: {}' }}", message), "application/json", 500)
}

/// Handler that sends static files relative to the current working directory.
pub fn static_file(req: &Request) -> Response {
    let mut res = Response::new();

    let cwd = env::current_dir().unwrap();
    let clean = replace_escape(&req.path);
    let mut fpath = PathBuf::from(&cwd);
    let mut fbuf: Vec<u8> = Vec::new();

    for chunk in clean.split('/') {
        if chunk == "" || chunk == "." || chunk == ".." {
            /* bzzzzt */
            continue;
        }

        fpath.push(&chunk);
    }

    let file = File::open(&fpath);

    match file {
        Ok(mut f)   => {
            match f.read_to_end(&mut fbuf) {
                Ok(_)   => {
                    res.set_code(200);
                    res.set_content_type("text/plain");
                    res.append(fbuf);
                },
                Err(e)  => {
                    return make_response(err_body("internal server error", e.description()), "text/html", 500);
                },
            }
        },
        Err(_)      => {
            return err_404(&req);
        }
    }

    res
}
<|endoftext|>


<commit_before>use iron::prelude::*;
use maud::{Markup, PreEscaped, Render};
use pulldown_cmark;

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            link rel="icon" type="image/png" href=(url_for!(r, "static", "path" => "icon.png")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, ""))
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: &str) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search"
                autocomplete="off" value=(value) /
        }
        script (PreEscaped(r#"
            var searchBox = document.getElementById('q')
            if (!searchBox.value) searchBox.select()
        "#))
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, ""))
    })
}

pub fn search_results<'u, I>(
    r: &Request, query: &str, results: I, correction: Option<String>) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, query))
        @if results.peek().is_none() {
            p "No results found."
        } @else if let Some(correction) = correction {
            p {
                "Showing results for "
                a href=(url_for!(r, "search", "q" => &correction[..])) strong (correction)
            }
        }
        @for (user, id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) {
                    (user_title(&id, user.ok()))
                }
            }
            @if let Ok(user) = user {
                (user_box(&id, user))
            }
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    layout(r, Some(&user_title(id, Some(user))), user_box(id, user))
}

fn user_title(id: &str, user: Option<&User>) -> String {
    if let Some(name) = user.and_then(|user| user.name.as_ref()) {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    }
}

fn user_box(id: &str, user: &User) -> Markup {
    html! {
        table {
            tr {
                th "GitHub"
                td a href={ "https://github.com/" (id) } (id)
            }
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown(x))
        }
    }
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a>(&'a str);

impl<'a> Render for Markdown<'a> {
    fn render_to(&self, buffer: &mut String) {
        let parser = pulldown_cmark::Parser::new(self.0);
        pulldown_cmark::html::push_html(buffer, parser);
    }
}
<commit_msg>Improve Markdown rendering<commit_after>use iron::prelude::*;
use maud::{Markup, PreEscaped, Render};
use pulldown_cmark::{self, Event, Parser, Tag};

use models::User;

fn layout(r: &Request, title: Option<&str>, body: Markup) -> Markup {
    layout_inner(r, title, title, body)
}

fn layout_inner(r: &Request, head_title: Option<&str>, body_title: Option<&str>, body: Markup) -> Markup {
    html! {
        (PreEscaped("<!DOCTYPE html>"))
        html {
            meta charset="utf-8" /
            title {
                @if let Some(head_title) = head_title {
                    (head_title) " - "
                }
                "Karkinos"
            }
            meta name="viewport" content="width=device-width" /
            link rel="stylesheet" href=(url_for!(r, "static", "path" => "styles.css")) /
            link rel="icon" type="image/png" href=(url_for!(r, "static", "path" => "icon.png")) /
            body {
                h1 a href="/" {
                    span.thecrab "🦀"
                    "Karkinos"
                }
                @if let Some(body_title) = body_title {
                    h2 a href=(r.url) title="Link to this page" (body_title)
                }
                (body)
            }
        }
    }
}

pub fn home(r: &Request) -> Markup {
    layout(r, None, html! {
        (search_form(r, ""))
        p {
            span.karkinos "KARKINOS"
            " is a database of people interested in the "
            a href="https://www.rust-lang.org" "Rust programming language"
            ". It uses the same data as "
            a href="http://rustaceans.org" "rustaceans.org"
            ", but presents it through a different interface."
        }
        p "I created Karkinos for these reasons:"
        ul {
            li "To provide access for users who browse with JavaScript disabled;"
            li "To rewrite the backend in Rust (instead of Node.js);"
            li {
                "As a proving ground for my template engine, "
                a href="https://github.com/lfairy/maud" "Maud"
                ";"
            }
            li "To screw around with CSS (this is the most important reason)."
        }
        p {
            "Karkinos is named after a very special "
            a href="https://en.wikipedia.org/wiki/Cancer_(constellation)#Names" "giant crab"
            "."
        }
        p {
            "The source code for this site can be found on "
            a href="https://github.com/lfairy/karkinos" "GitHub"
            "."
        }
    })
}

fn search_form(r: &Request, value: &str) -> Markup {
    html! {
        form action=(url_for!(r, "search")) {
            input name="q" id="q" type="search" placeholder="Search"
                autocomplete="off" value=(value) /
        }
        script (PreEscaped(r#"
            var searchBox = document.getElementById('q')
            if (!searchBox.value) searchBox.select()
        "#))
    }
}

pub fn not_found(r: &Request) -> Markup {
    layout(r, Some("Not found"), html! {
        p {
            "The page at "
            strong (r.url)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

pub fn search(r: &Request) -> Markup {
    layout(r, Some("Search"), html! {
        (search_form(r, ""))
    })
}

pub fn search_results<'u, I>(
    r: &Request, query: &str, results: I, correction: Option<String>) -> Markup where
    I: Iterator<Item=(Result<&'u User, &'u str>, String, u64)>,
{
    let title = format!("Search results for “{}”", query);
    let mut results = results.peekable();
    layout_inner(r, Some(&title), None, html! {
        (search_form(r, query))
        @if results.peek().is_none() {
            p "No results found."
        } @else if let Some(correction) = correction {
            p {
                "Showing results for "
                a href=(url_for!(r, "search", "q" => &correction[..])) strong (correction)
            }
        }
        @for (user, id, weight) in results {
            h3 title={ "Weight: " (weight) } {
                a href=(url_for!(r, "user", "id" => &id[..])) {
                    (user_title(&id, user.ok()))
                }
            }
            @if let Ok(user) = user {
                (user_box(&id, user, 3))
            }
            hr /
        }
    })
}

pub fn user(r: &Request, id: &str, user: &User) -> Markup {
    layout(r, Some(&user_title(id, Some(user))), user_box(id, user, 2))
}

fn user_title(id: &str, user: Option<&User>) -> String {
    if let Some(name) = user.and_then(|user| user.name.as_ref()) {
        format!("{} ({})", name, id)
    } else {
        id.to_string()
    }
}

fn user_box(id: &str, user: &User, demote_headers: u32) -> Markup {
    html! {
        table {
            tr {
                th "GitHub"
                td a href={ "https://github.com/" (id) } (id)
            }
            @if let Some(ref nick) = user.irc {
                tr {
                    th "IRC"
                    td {
                        (nick)
                        @if !user.irc_channels.is_empty() {
                            " on "
                            @for (i, channel) in user.irc_channels.iter().enumerate() {
                                @if i > 0 { ", " }
                                a href={ "irc://irc.mozilla.org/" (channel) } {
                                    "#" (channel)
                                }
                            }
                        }
                    }
                }
            }
            @if let Some(ref x) = user.discourse {
                tr {
                    th "Discourse"
                    td a href={ "https://users.rust-lang.org/users/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.reddit {
                tr {
                    th "Reddit"
                    td a href={ "https://reddit.com/user/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.twitter {
                tr {
                    th "Twitter"
                    td a href={ "https://twitter.com/" (x) } (x)
                }
            }
            @if let Some(ref x) = user.website {
                tr {
                    th "Website"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.blog {
                tr {
                    th "Blog"
                    td a href=(x) (x)
                }
            }
            @if let Some(ref x) = user.email {
                tr {
                    th "Email"
                    td a href={ "mailto:" (x) } (x)
                }
            }
        }
        @if let Some(ref x) = user.notes {
            div.notes (Markdown { text: x, demote_headers: demote_headers })
        }
    }
}

pub fn user_error(r: &Request, id: &str, error: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " exists, but their entry could not be parsed."
        }
        p {
            "(Error: " (error) ")"
        }
    })
}

pub fn user_not_found(r: &Request, id: &str) -> Markup {
    layout(r, Some(id), html! {
        p {
            "The user "
            strong (id)
            " could not be found."
        }
        p a href="/" "‹ Back to home page"
    })
}

struct Markdown<'a> {
    text: &'a str,
    demote_headers: u32,
}

impl<'a> Render for Markdown<'a> {
    fn render_to(&self, buffer: &mut String) {
        let parser = Parser::new_ext(self.text, pulldown_cmark::OPTION_ENABLE_TABLES);
        // Demote headers
        let parser = parser.map(|event| match event {
            Event::Start(Tag::Header(level)) =>
                Event::Start(Tag::Header(level + self.demote_headers as i32)),
            Event::End(Tag::Header(level)) =>
                Event::End(Tag::Header(level + self.demote_headers as i32)),
            _ => event,
        });
        pulldown_cmark::html::push_html(buffer, parser);
    }
}
<|endoftext|>


<commit_before>use std::cell::RefCell;
use std::rc::Rc;

use super::super::target::bytecode::layout::{Function, Instruction, Reg, Unit};

use super::value::{NativeFunction, Value};

// Frames can live outside of the stack (eg. closures) and can be mutated from
// places outside the stack (again, closures), therefore we need reference
// counting (`Rc`) and interior mutability (`RefCell`).
type SharedFrame = Rc<RefCell<Frame>>;

// The first three fields should *not* be changed after the frame
// is initialized.
struct Frame {
    unit: Rc<Unit>,
    function: Rc<Function>,
    lexical_parent: Option<SharedFrame>,
    return_register: Reg,
    registers: Vec<Value>,
    locals: Vec<Value>,
    current_block: usize,
    current_address: usize,
}

impl Frame {
    fn new(
        unit: Rc<Unit>,
        function: Rc<Function>,
        lexical_parent: Option<SharedFrame>,
        return_register: Reg,
    ) -> Self {
        let registers = function.registers;
        let locals = function.locals;
        Self {
            unit,
            function,
            lexical_parent,
            return_register,
            registers: vec![Value::Null; registers as usize],
            locals: vec![Value::Null; locals as usize],
            current_block: 0,
            current_address: 0,
        }
    }

    #[inline]
    fn current(&self) -> Instruction {
        let block = &self.function.basic_blocks[self.current_block];
        block.instructions[self.current_address].clone()
    }

    #[inline]
    fn offset_register(index: Reg) -> usize {
        (index as usize) - 1
    }

    fn advance(&mut self) {
        self.current_address += 1;
    }

    fn read_register(&self, index: Reg) -> Value {
        self.registers[Frame::offset_register(index)].clone()
    }

    fn write_register(&mut self, index: Reg, value: Value) {
        if index == 0 {
            return;
        }
        self.registers[Frame::offset_register(index)] = value;
    }

    fn get_local(&self, index: u8) -> Value {
        self.locals[index as usize].clone()
    }

    fn get_local_lexical(&self, name: &String) -> Value {
        let index = self
            .function
            .locals_names
            .iter()
            .position(|local| local == name);
        if let Some(index) = index {
            self.locals[index].clone()
        } else {
            if let Some(ref lexical_parent) = self.lexical_parent {
                lexical_parent.borrow().get_local_lexical(name)
            } else {
                panic!("Out of parents")
            }
        }
    }

    fn set_local(&mut self, index: u8, value: Value) {
        self.locals[index as usize] = value;
    }
}

pub struct Vm {
    stack: Vec<SharedFrame>,
}

enum Action {
    // Advance to the next instruction.
    Advance,
    // Execute a dynamic function call (ie. push onto the stack).
    CallDynamic(Reg, Value, Vec<Value>),
    CallNative(Reg, NativeFunction, Vec<Value>),
    Return(Value),
}

fn prelude_println(arguments: Vec<Value>) -> Value {
    if let Some(argument) = arguments.first() {
        match argument {
            Value::Integer(value) => println!("{}", value),
            _ => unreachable!(),
        }
    };
    Value::Null
}

impl Vm {
    pub fn run_main(unit: Rc<Unit>) {
        let prelude = Vm::build_prelude();
        let main_function = Rc::new(unit.functions[0].clone());
        let frame = Frame::new(unit, main_function, Some(prelude), 0);
        let mut vm = Self {
            stack: vec![Rc::new(RefCell::new(frame))],
        };
        vm.run();
    }

    fn build_prelude() -> SharedFrame {
        let prelude_unit = Unit {
            functions: vec![Function {
                id: 0,
                name: "prelude".to_string(),
                registers: 0,
                basic_blocks: vec![],
                locals: 1,
                locals_names: vec!["println".to_string()],
            }],
        };
        let prelude_main_function = prelude_unit.functions[0].clone();
        let mut prelude = Frame::new(
            Rc::new(prelude_unit),
            Rc::new(prelude_main_function),
            None,
            0,
        );
        prelude.set_local(
            0,
            Value::NativeFunction(NativeFunction::new(Rc::new(prelude_println))),
        );
        Rc::new(RefCell::new(prelude))
    }

    fn run(&mut self) {
        loop {
            let top = self.stack.last().expect("Empty stack");
            let instruction = top.borrow().current();
            let action = Vm::dispatch(&instruction, &mut top.borrow_mut());
            // Apply side effects which will impact the whole VM. We isolated
            // frame-level side effects inside of `Vm::dispatch` to make the
            // borrow-checker happy.
            match action {
                Action::Advance => top.borrow_mut().advance(),
                // Due to borrow-checker rules we cannot have the side effects
                // of a call happen within `dispatch`.
                Action::CallDynamic(return_register, target, arguments) => {
                    let (unit, function) = target.dynamic_function().unwrap();
                    let frame = Rc::new(RefCell::new(Frame::new(
                        unit,
                        function,
                        None,
                        return_register,
                    )));
                    self.stack.push(frame)
                }
                Action::CallNative(return_register, target, arguments) => {
                    let result = target.call(arguments);
                    let mut top = top.borrow_mut();
                    top.write_register(return_register, result);
                    top.advance();
                }
                Action::Return(value) => {
                    let popped = self.stack.pop().expect("Empty stack");
                    let return_register = popped.borrow().return_register;
                    match self.stack.last() {
                        Some(top) => {
                            let mut top = top.borrow_mut();
                            top.write_register(return_register, value);
                            top.advance();
                        }
                        // Returning from the top frame.
                        None => return,
                    }
                }
                _ => unreachable!(),
            }
        }
    }

    // Decodes the instruction, applies any frame-level side effects, and
    // returns an `Action` describing stack/VM-level side effects.
    #[inline]
    fn dispatch(instruction: &Instruction, top: &mut Frame) -> Action {
        match instruction {
            Instruction::GetLocal(lval, index) => {
                top.write_register(*lval, top.get_local(*index));
                Action::Advance
            }
            Instruction::GetLocalLexical(lval, name) => {
                top.write_register(*lval, top.get_local_lexical(name));
                Action::Advance
            }
            Instruction::SetLocal(index, rval) => {
                top.set_local(*index, top.read_register(*rval));
                Action::Advance
            }
            Instruction::MakeInteger(lval, value) => {
                top.write_register(*lval, Value::Integer(*value));
                Action::Advance
            }
            Instruction::Call(lval, target, arguments) => {
                let target = top.read_register(*target);
                let arguments = arguments
                    .iter()
                    .map(|argument| top.read_register(*argument))
                    .collect::<Vec<Value>>();
                match target {
                    Value::DynamicFunction(_, _) => Action::CallDynamic(*lval, target, arguments),
                    Value::NativeFunction(native_function) => {
                        Action::CallNative(*lval, native_function, arguments)
                    }
                    _ => panic!("Cannot call"),
                }
            }
            Instruction::ReturnNull => Action::Return(Value::Null),
            _ => panic!("Cannot dispatch: {:?}", instruction),
        }
    }
}
<commit_msg>Combine dispatch into one method<commit_after>use std::cell::RefCell;
use std::process::exit;
use std::rc::Rc;

use super::super::target::bytecode::layout::{Function, Instruction, Reg, Unit};

use super::value::{NativeFunction, Value};

// Frames can live outside of the stack (eg. closures) and can be mutated from
// places outside the stack (again, closures), therefore we need reference
// counting (`Rc`) and interior mutability (`RefCell`).
type SharedFrame = Rc<RefCell<Frame>>;

// The first three fields should *not* be changed after the frame
// is initialized.
struct Frame {
    unit: Rc<Unit>,
    function: Rc<Function>,
    lexical_parent: Option<SharedFrame>,
    return_register: Reg,
    registers: Vec<Value>,
    locals: Vec<Value>,
    current_block: usize,
    current_address: usize,
}

impl Frame {
    fn new(
        unit: Rc<Unit>,
        function: Rc<Function>,
        lexical_parent: Option<SharedFrame>,
        return_register: Reg,
    ) -> Self {
        let registers = function.registers;
        let locals = function.locals;
        Self {
            unit,
            function,
            lexical_parent,
            return_register,
            registers: vec![Value::Null; registers as usize],
            locals: vec![Value::Null; locals as usize],
            current_block: 0,
            current_address: 0,
        }
    }

    #[inline]
    fn current(&self) -> Instruction {
        let block = &self.function.basic_blocks[self.current_block];
        block.instructions[self.current_address].clone()
    }

    #[inline]
    fn offset_register(index: Reg) -> usize {
        (index as usize) - 1
    }

    fn advance(&mut self) {
        self.current_address += 1;
    }

    fn read_register(&self, index: Reg) -> Value {
        self.registers[Frame::offset_register(index)].clone()
    }

    fn write_register(&mut self, index: Reg, value: Value) {
        if index == 0 {
            return;
        }
        self.registers[Frame::offset_register(index)] = value;
    }

    fn get_local(&self, index: u8) -> Value {
        self.locals[index as usize].clone()
    }

    fn get_local_lexical(&self, name: &String) -> Value {
        let index = self
            .function
            .locals_names
            .iter()
            .position(|local| local == name);
        if let Some(index) = index {
            self.locals[index].clone()
        } else {
            if let Some(ref lexical_parent) = self.lexical_parent {
                lexical_parent.borrow().get_local_lexical(name)
            } else {
                panic!("Out of parents")
            }
        }
    }

    fn set_local(&mut self, index: u8, value: Value) {
        self.locals[index as usize] = value;
    }
}

pub struct Vm {
    stack: Vec<SharedFrame>,
}

enum Action {
    None,
    Push(SharedFrame),
    Pop(Value),
}

fn prelude_println(arguments: Vec<Value>) -> Value {
    if let Some(argument) = arguments.first() {
        match argument {
            Value::Integer(value) => println!("{}", value),
            _ => unreachable!(),
        }
    };
    Value::Null
}

impl Vm {
    pub fn run_main(unit: Rc<Unit>) {
        let prelude = Vm::build_prelude();
        let main_function = Rc::new(unit.functions[0].clone());
        let frame = Frame::new(unit, main_function, Some(prelude), 0);
        let mut vm = Self {
            stack: vec![Rc::new(RefCell::new(frame))],
        };
        vm.run();
    }

    fn build_prelude() -> SharedFrame {
        let prelude_unit = Unit {
            functions: vec![Function {
                id: 0,
                name: "prelude".to_string(),
                registers: 0,
                basic_blocks: vec![],
                locals: 1,
                locals_names: vec!["println".to_string()],
            }],
        };
        let prelude_main_function = prelude_unit.functions[0].clone();
        let mut prelude = Frame::new(
            Rc::new(prelude_unit),
            Rc::new(prelude_main_function),
            None,
            0,
        );
        prelude.set_local(
            0,
            Value::NativeFunction(NativeFunction::new(Rc::new(prelude_println))),
        );
        Rc::new(RefCell::new(prelude))
    }

    fn run(&mut self) {
        loop {
            match self.dispatch() {
                Some(code) => exit(code),
                None => (),
            }
        }
    }

    fn dispatch(&mut self) -> Option<i32> {
        use self::Action::*;

        let top = self.stack.last().expect("Empty stack");
        let instruction = top.borrow().current();

        let action = {
            let top: &mut Frame = &mut top.borrow_mut();
            match &instruction {
                Instruction::GetLocal(lval, index) => {
                    top.write_register(*lval, top.get_local(*index));
                    top.advance();
                    None
                }
                Instruction::GetLocalLexical(lval, name) => {
                    top.write_register(*lval, top.get_local_lexical(name));
                    top.advance();
                    None
                }
                Instruction::SetLocal(index, rval) => {
                    top.set_local(*index, top.read_register(*rval));
                    top.advance();
                    None
                }
                Instruction::MakeInteger(lval, value) => {
                    top.write_register(*lval, Value::Integer(*value));
                    top.advance();
                    None
                }
                Instruction::Call(lval, target, arguments) => {
                    let return_register = *lval;
                    let target = top.read_register(*target);
                    let arguments = arguments
                        .iter()
                        .map(|argument| top.read_register(*argument))
                        .collect::<Vec<Value>>();
                    match target {
                        Value::DynamicFunction(_, _) => {
                            let (unit, function) = target.dynamic_function().unwrap();
                            let frame = Rc::new(RefCell::new(Frame::new(
                                unit,
                                function,
                                Option::None,
                                return_register,
                            )));
                            Push(frame)
                        }
                        Value::NativeFunction(native_function) => {
                            let result = native_function.call(arguments);
                            top.write_register(return_register, result);
                            top.advance();
                            None
                        }
                        _ => panic!("Cannot call"),
                    }
                }
                Instruction::Return(rval) => {
                    Pop(top.read_register(*rval))
                }
                Instruction::ReturnNull => Pop(Value::Null),
                _ => panic!("Cannot dispatch: {:?}", instruction),
            }
        };
        match action {
            Push(frame) => self.stack.push(frame),
            Pop(return_value) => {
                let popped = self.stack.pop().expect("Empty stack");
                let return_register = popped.borrow().return_register;
                match self.stack.last() {
                    Option::Some(top) => {
                        let mut top = top.borrow_mut();
                        top.write_register(return_register, return_value);
                        top.advance();
                    }
                    // Returning from the top frame.
                    Option::None => return Some(0),
                }
            }
            None => (),
        };
        Option::None
    }
}
<|endoftext|>


<commit_before>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This program exercises the Rust GIF decoder in https://github.com/Geal/gif.rs
//
// Wuffs doesn't depend on Rust or Nom (a parser combinator library written in
// Rust) per se, but this program gives some comparitive data on how fast a
// Rust GIF decoder could perform.
//
// To run this program, do "cargo run --release > /dev/null" from the parent
// directory (the directory containing the Cargo.toml file). See the eprint
// comment below for why we redirect to /dev/null.

extern crate gif;

use std::time::Instant;

// These constants are hard-coded to the harvesters.gif test image. As of
// 2018-01-27, the https://github.com/Geal/gif.rs library's src/lib.rs' Decoder
// implementation is incomplete, and doesn't expose enough API to calculate
// these from the source GIF image.
const WIDTH: usize = 1165;
const HEIGHT: usize = 859;
const BYTES_PER_PIXEL: usize = 3; // Red, green, blue.
const NUM_BYTES: usize = WIDTH * HEIGHT * BYTES_PER_PIXEL;
const COLOR_TABLE_ELEMENT_COUNT: u16 = 256;
const COLOR_TABLE_OFFSET: usize = 13;
const GRAPHIC_BLOCK_OFFSET: usize = 782;
const FIRST_PIXEL: u8 = 1; // Top left pixel's red component is 0x01.
const LAST_PIXEL: u8 = 3; // Bottom right pixel's blue component is 0x03.

fn main() {
    let mut dst: Vec<u8> = Vec::with_capacity(NUM_BYTES);
    // This unsafe code is based on decode_lzw_test in github.com/Geal/gif.rs's
    // parser.rs.
    unsafe {
        dst.set_len(NUM_BYTES);
    }

    let src = include_bytes!("../../../test/testdata/harvesters.gif");

    let start = Instant::now();

    const REPS: u32 = 50;
    for _ in 0..REPS {
        decode(&mut dst[..], src);
    }

    let elapsed = start.elapsed();
    let elapsed_nanos = elapsed.as_secs() * 1_000_000_000 + (elapsed.subsec_nanos() as u64);

    let total_pixels: u64 = ((WIDTH * HEIGHT) as u64) * (REPS as u64);
    let kb_per_s: u64 = total_pixels * 1_000_000 / elapsed_nanos;

    // Use eprint instead of print because the https://github.com/Geal/gif.rs
    // library can print its own debugging messages. When running this program,
    // it can be useful to redirect stdout (but not stderr) to /dev/null.
    eprint!("{}.{:03} MB/s\n", kb_per_s / 1_000, kb_per_s % 1_000);
}

fn decode(dst: &mut [u8], src: &[u8]) {
    // Set up the hard-coded sanity check, executed below.
    dst[0] = 0;
    dst[NUM_BYTES - 1] = 0;

    // This nested code is based on decode_lzw_test in github.com/Geal/gif.rs's
    // parser.rs.

    match gif::parser::color_table(&src[COLOR_TABLE_OFFSET..], COLOR_TABLE_ELEMENT_COUNT) {
        Ok((_, colors)) => {
            match gif::parser::graphic_block(&src[GRAPHIC_BLOCK_OFFSET..]) {
                Ok((_, gif::parser::Block::GraphicBlock(_, rendering))) => {
                    match rendering {
                        gif::parser::GraphicRenderingBlock::TableBasedImage(_,
                                                                            code_size,
                                                                            blocks) => {
                            match gif::lzw::decode_lzw(&colors, code_size as usize, blocks, dst) {
                                Ok(num_bytes) => {
                                    if num_bytes != NUM_BYTES {
                                        panic!("wrong num_bytes")
                                    }
                                    // A hard-coded sanity check that we
                                    // decoded the image's pixel data properly.
                                    if (dst[0] != FIRST_PIXEL) ||
                                        (dst[NUM_BYTES - 1] != LAST_PIXEL)
                                    {
                                        panic!("wrong dst pixels")
                                    }
                                }
                                _ => panic!("could not decode"),
                            }
                        }
                        _ => panic!("plaintext extension"),
                    }
                }
                _ => panic!("cannot parse graphic block"),
            }
        }
        _ => panic!("cannot parse global color table"),
    }
}
<commit_msg>Rust style fixes<commit_after>// Copyright 2018 The Wuffs Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

// This program exercises the Rust GIF decoder in https://github.com/Geal/gif.rs
//
// Wuffs doesn't depend on Rust or Nom (a parser combinator library written in
// Rust) per se, but this program gives some comparitive data on how fast a
// Rust GIF decoder could perform.
//
// To run this program, do "cargo run --release > /dev/null" from the parent
// directory (the directory containing the Cargo.toml file). See the eprint
// comment below for why we redirect to /dev/null.

extern crate gif;

use std::time::Instant;

// These constants are hard-coded to the harvesters.gif test image. As of
// 2018-01-27, the https://github.com/Geal/gif.rs library's src/lib.rs' Decoder
// implementation is incomplete, and doesn't expose enough API to calculate
// these from the source GIF image.
const WIDTH: usize = 1165;
const HEIGHT: usize = 859;
const BYTES_PER_PIXEL: usize = 3; // Red, green, blue.
const NUM_BYTES: usize = WIDTH * HEIGHT * BYTES_PER_PIXEL;
const COLOR_TABLE_ELEMENT_COUNT: u16 = 256;
const COLOR_TABLE_OFFSET: usize = 13;
const GRAPHIC_BLOCK_OFFSET: usize = 782;
const FIRST_PIXEL: u8 = 1; // Top left pixel's red component is 0x01.
const LAST_PIXEL: u8 = 3; // Bottom right pixel's blue component is 0x03.

fn main() {
    let mut dst = [0; NUM_BYTES];
    let src = include_bytes!("../../../test/testdata/harvesters.gif");

    let start = Instant::now();

    const REPS: u32 = 50;
    for _ in 0..REPS {
        decode(&mut dst[..], src);
    }

    let elapsed = start.elapsed();
    let elapsed_nanos = elapsed.as_secs() * 1_000_000_000 + (elapsed.subsec_nanos() as u64);

    let total_pixels: u64 = ((WIDTH * HEIGHT) as u64) * (REPS as u64);
    let kp_per_s: u64 = total_pixels * 1_000_000 / elapsed_nanos;

    // Use eprint instead of print because the https://github.com/Geal/gif.rs
    // library can print its own debugging messages (this is filed as
    // https://github.com/Geal/gif.rs/issues/4). When running this program, it
    // can be useful to redirect stdout (but not stderr) to /dev/null.
    eprint!(
        "{}.{:03} megapixels/second\n",
        kp_per_s / 1_000,
        kp_per_s % 1_000
    );
}

fn decode(dst: &mut [u8], src: &[u8]) {
    // Set up the hard-coded sanity check, executed below.
    dst[0] = 0;
    dst[NUM_BYTES - 1] = 0;

    let (_, colors) =
        gif::parser::color_table(&src[COLOR_TABLE_OFFSET..], COLOR_TABLE_ELEMENT_COUNT).unwrap();

    let (_, block) = gif::parser::graphic_block(&src[GRAPHIC_BLOCK_OFFSET..]).unwrap();

    let rendering = match block {
        gif::parser::Block::GraphicBlock(_, x) => x,
        _ => panic!("not a graphic block"),
    };

    let (code_size, blocks) = match rendering {
        gif::parser::GraphicRenderingBlock::TableBasedImage(_, x, y) => (x, y),
        _ => panic!("not a table based image"),
    };

    let num_bytes = gif::lzw::decode_lzw(&colors, code_size as usize, blocks, dst).unwrap();

    if num_bytes != NUM_BYTES {
        panic!("wrong num_bytes")
    }

    // A hard-coded sanity check that we decoded the pixel data correctly.
    if (dst[0] != FIRST_PIXEL) || (dst[NUM_BYTES - 1] != LAST_PIXEL) {
        panic!("wrong dst pixels")
    }
}
<|endoftext|>