<commit_before>extern mod std;

use core::libc::{c_char, c_int, c_void};
use core::option::{Some, None};
use core::result::{Ok, Err};
use core::either::Either;
use core::result::Result;
use consts::*;

enum Pcre {}
enum PcreExtra {}
struct PcreRes {
    p: *Pcre,
    drop { unsafe { c::free(self.p as *c_void); } }
}

/// The result type of `compile`
pub type CompileResult = Result<Pattern, CompileErr>;

/// The result type of `exec`
pub type ExecResult = Result<Match, ExecErr>;

/// The result type of `search`
pub type SearchResult = Result<Match, RegexErr>;

// The result type of `replace`
pub type ReplaceResult = Result<@~str, RegexErr>;

/// The type that represents compile error
pub struct CompileErr {
    code: int,
    reason: @~str,
    offset: uint,
}

/// The type that represents exec error
pub type ExecErr = int;

/// Either compile or exec error
pub enum RegexErr {
    CompileErr(CompileErr),
    ExecErr(ExecErr),
}

/// Compiled regular expression
pub struct Pattern {
    str: @~str,
    priv pcre_res: @PcreRes,
}

/// Match
pub struct Match {
    subject: @~str,
    pattern: Pattern,
    priv captures: @~[int],
}

#[nolink]
#[abi = "cdecl"]
extern mod c {
    fn free(p: *c_void);
}

extern mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *Pcre;
    fn pcre_exec(code: *Pcre, extra: *PcreExtra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *Pcre, extra: *PcreExtra,
                     what: c_int, where: *c_void) -> c_int;
    fn pcre_get_stringnumber(code: *Pcre, name: *c_char) -> c_int;
}

pub trait PatternUtil {
    fn info_capture_count(self) -> uint;
    fn info_name_count(self) -> uint;
    fn info_name_entry_size(self) -> uint;
    fn with_name_table(self, blk: fn(*u8));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl Pattern: PatternUtil {
    fn info_capture_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_CAPTURECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert count >= 0 as c_int;
        return count as uint;
    }

    fn info_name_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert count >= 0 as c_int;
        return count as uint;
    }

    fn info_name_entry_size(self) -> uint {
        let size = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMEENTRYSIZE as c_int,
                                ptr::addr_of(&size) as *c_void);
        }
        assert size >= 0 as c_int;
        return size as uint;
    }

    fn with_name_table(self, blk: fn(*u8)) {
        let table = ptr::null::<u8>();
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMETABLE as c_int,
                                ptr::addr_of(&table) as *c_void);
        }
        assert table != ptr::null::<u8>();
        blk(table);
    }

    fn group_count(self) -> uint {
        return self.info_capture_count();
    }

    fn group_names(self) -> ~[~str] {
        let count = self.info_name_count();
        if count == 0u { return ~[]; }
        let size = self.info_name_entry_size();
        let mut names: ~[~str] = ~[];
        do self.with_name_table |table| {
            for uint::range(0u, count) |i| {
                unsafe {
                    let p = ptr::offset(table, size * i + 2u);
                    let s = str::raw::from_c_str(p as *c_char);
                    vec::push(&mut names, s);
                }
            }
        }
        return names;
    }
}

pub trait PatternLike {
    fn compile(&self, options: int) -> CompileResult;
}

impl &str: PatternLike {
    fn compile(&self, options: int) -> CompileResult { compile(*self, options) }
}

impl ~str: PatternLike {
    fn compile(&self, options: int) -> CompileResult { compile(*self, options) }
}

impl @str: PatternLike {
    fn compile(&self, options: int) -> CompileResult { compile(*self, options) }
}

impl Pattern: PatternLike {
    fn compile(&self, _options: int) -> CompileResult { Ok(*self) }
}

impl CompileResult: PatternLike {
    fn compile(&self, _options: int) -> CompileResult { *self }
}

pub trait MatchExtensions {
    fn matched(self) -> ~str;
    fn prematch(self) -> ~str;
    fn postmatch(self) -> ~str;
    fn begin(self) -> uint;
    fn end(self) -> uint;
    fn group(self, i: uint) -> Option<@~str>;
    fn named_group(self, name: &str) -> Option<@~str>;
    fn subgroups(self) -> ~[~str];
    fn subgroups_iter(self, blk: fn(&str));
    fn group_count(self) -> uint;
    fn group_names(self) -> ~[~str];
}

impl Match: MatchExtensions {
    fn matched(self) -> ~str {
        return str::slice(*self.subject, self.begin(), self.end());
    }

    fn prematch(self) -> ~str {
        return str::slice(*self.subject, 0u, self.begin());
    }

    fn postmatch(self) -> ~str {
        return str::slice(*self.subject ,self.end(),
                          str::char_len(*self.subject));
    }

    fn begin(self) -> uint {
        return self.captures[0] as uint;
    }

    fn end(self) -> uint {
        return self.captures[1] as uint;
    }

    fn group(self, i: uint) -> Option<@~str> {
        if i > self.group_count() {
            return None;
        }
        let i1 = self.captures[i * 2u];
        let i2 = self.captures[i * 2u + 1u];
        if(i1 < 0 || i2 < 0) {
            return None;
        }
        return Some(@str::slice(*self.subject, i1 as uint, i2 as uint));
    }

    fn named_group(self, name: &str) -> Option<@~str> {
        let i =  unsafe {
            str::as_buf(name, |s, _n| {
                pcre::pcre_get_stringnumber(self.pattern.pcre_res.p,
                                            s as *c_char)
            })
        };
        if i <= 0 as c_int { return None; }
        return self.group(i as uint);
    }

    fn subgroups(self) -> ~[~str] {
        let mut v = ~[];
        vec::reserve(&mut v, self.group_count());
        do self.subgroups_iter |subgroup| {
            vec::push(&mut v, str::from_slice(subgroup));
        }
        return v;
    }

    fn subgroups_iter(self, blk: fn(&str)) {
        for uint::range(1u, self.group_count() + 1u) |i| {
            match self.group(i) {
              Some(s) => blk(*s),
              None => die!(),
            }
        }
    }

    fn group_count(self) -> uint {
        return vec::len(*self.captures) / 2u - 1u;
    }

    fn group_names(self) -> ~[~str] {
        return self.pattern.group_names();
    }
}

pub fn compile(pattern: &str, options: int) -> CompileResult {
    if options | COMPILE_OPTIONS != COMPILE_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = unsafe {
        str::as_buf(pattern, |pat, _n| {
            pcre::pcre_compile2(pat as *c_char,
                                options as c_int,
                                ptr::addr_of(&errcode),
                                ptr::addr_of(&errreason),
                                ptr::addr_of(&erroffset),
                                ptr::null())
        })
    };
    if p == ptr::null() {
        let reason = unsafe { @str::raw::from_c_str(errreason) };
        return Err(CompileErr {code: errcode as int,
                               reason: reason,
                               offset: erroffset as uint});
    }
    return Ok(Pattern {str: @str::from_slice(pattern),
                       pcre_res: @PcreRes {p: p}});
}

pub fn exec(pattern: Pattern,
        subject: &str, offset: uint,
        options: int) -> ExecResult {

    if (options | EXEC_OPTIONS) != EXEC_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid

    let count = (pattern.info_capture_count() + 1u) as c_int;
    let mut ovec = vec::from_elem((count as uint) * 3u, 0u as c_int);

    let ret_code = unsafe {
        str::as_buf(subject, |s, _n| {
            pcre::pcre_exec(pattern.pcre_res.p, ptr::null(),
                            s as *c_char, str::len(subject) as c_int,
                            offset as c_int, options as c_int,
                            vec::raw::to_ptr(ovec) as *c_int,
                            count * (3 as c_int)) as int
        })
    };

    if ret_code < 0 { return Err(ret_code as ExecErr); }

    // Truncate the working space.
    unsafe { vec::raw::set_len(&mut ovec, count as uint * 2u) }

    let mut captures: ~[int] = ~[];
    vec::reserve(&mut captures, vec::len(ovec));
    for ovec.each |o| {
        vec::push(&mut captures, *o as int);
    }
    assert vec::len(captures) % 2u == 0u;

    return Ok(Match {subject: @str::from_slice(subject),
                     pattern: pattern,
                     captures: @captures});
}

pub fn search<T: PatternLike>(pattern: T, subject: &str,
                              options: int) -> SearchResult {
    return search_from(pattern, subject, 0u, options);
}

pub fn search_from<T: PatternLike>(pattern: T, subject: &str,
                                   offset: uint, options: int) -> SearchResult {
    assert offset <= str::len(subject);

    let c_opts = options & COMPILE_OPTIONS;
    let e_opts = options & EXEC_OPTIONS;

    let c = pattern.compile(c_opts);
    match c {
        Ok(pattern) => {
            let e = exec(pattern, subject, offset, e_opts);
            match e {
                Ok(m) => {
                    return Ok(m);
                }
                Err(e_err) => {
                    return Err(ExecErr(e_err));
                }
            }
        }
        Err(c_err) => {
            return Err(CompileErr(c_err));
        }
    }
}

pub fn replace<T: PatternLike Copy>(pattern: T, subject: &str, repl: &str,
                                    options: int) -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_from<T: PatternLike Copy>(pattern: T, subject: &str, repl: &str,
                                         offset: uint, options: int)
                                         -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_fn<T: PatternLike Copy>(pattern: T, subject: &str,
                                       repl_fn: fn(Match) -> ~str,
                                       options: int)
                                       -> ReplaceResult {
    return replace_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_fn_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                            repl_fn: fn(Match) -> ~str,
                                            offset: uint,
                                            options: int)
                                            -> ReplaceResult {
    let r = search_from(pattern, subject, offset, options);
    match r {
        Ok(m) => {
            return Ok(@(m.prematch() + repl_fn(m) + m.postmatch()));
        }
        Err(e) => { return Err(e); }
    }
}

pub fn replace_all<T: PatternLike Copy>(pattern: T, subject: &str,
                                        repl: &str,
                                        options: int)
                                        -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, 0u, options);
}

pub fn replace_all_fn<T: PatternLike Copy>(pattern: T, subject: &str,
                                           repl_fn: fn(Match) -> ~str,
                                           options: int)
                                           -> ReplaceResult {
    return replace_all_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub fn replace_all_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                             repl: &str,
                                             offset: uint,
                                             options: int)
                                             -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, offset, options);
}

pub fn replace_all_fn_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                                repl_fn: fn(Match) -> ~str,
                                                offset: uint,
                                                options: int)
                                                -> ReplaceResult {
    let mut offset = offset;
    let subject_len = str::len(subject);
    assert offset <= subject_len;

    let mut s = str::slice(subject, 0, offset);
    loop {
        let r = search_from(pattern, subject, offset, options);
        match r {
            Ok(m) => {
                s += str::slice(subject, offset, m.begin());
                s += repl_fn(m);
                offset = m.end();
            }
            Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => {
                if offset != subject_len {
                    s += str::slice(subject, offset, subject_len);
                }
                break;
            }
            Err(e) => {
                return Err(copy e);
            }
        }
    }
    return Ok(@s);
}

pub fn fmt_compile_err(e: CompileErr) -> ~str {
    return fmt!("error %d: %s at offset %u", e.code, *e.reason, e.offset);
}

/// Return true iff `sr` indicates that the subject did not match the pattern
pub pure fn is_nomatch(sr: SearchResult) -> bool {
    match sr {
        Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => true,
        _ => false,
    }
}
<commit_msg>Purify a majority of functions<commit_after>extern mod std;

use core::libc::{c_char, c_int, c_void};
use core::option::{Some, None};
use core::result::{Ok, Err};
use core::either::Either;
use core::result::Result;
use consts::*;

enum Pcre {}
enum PcreExtra {}
struct PcreRes {
    p: *Pcre,
    drop { unsafe { c::free(self.p as *c_void); } }
}

/// The result type of `compile`
pub type CompileResult = Result<Pattern, CompileErr>;

/// The result type of `exec`
pub type ExecResult = Result<Match, ExecErr>;

/// The result type of `search`
pub type SearchResult = Result<Match, RegexErr>;

// The result type of `replace`
pub type ReplaceResult = Result<@~str, RegexErr>;

/// The type that represents compile error
pub struct CompileErr {
    code: int,
    reason: @~str,
    offset: uint,
}

/// The type that represents exec error
pub type ExecErr = int;

/// Either compile or exec error
pub enum RegexErr {
    CompileErr(CompileErr),
    ExecErr(ExecErr),
}

/// Compiled regular expression
pub struct Pattern {
    str: @~str,
    priv pcre_res: @PcreRes,
}

/// Match
pub struct Match {
    subject: @~str,
    pattern: Pattern,
    priv captures: @~[int],
}

#[nolink]
#[abi = "cdecl"]
extern mod c {
    fn free(p: *c_void);
}

extern mod pcre {
    fn pcre_compile2(pattern: *c_char, options: c_int,
                     errorcodeptr: *c_int,
                     errptr: **c_char, erroffset: *c_int,
                     tableptr: *c_char) -> *Pcre;
    fn pcre_exec(code: *Pcre, extra: *PcreExtra,
                 subject: *c_char, length: c_int, startoffset: c_int,
                 options: c_int, ovector: * c_int, ovecsize: c_int) -> c_int;
    fn pcre_fullinfo(code: *Pcre, extra: *PcreExtra,
                     what: c_int, where: *c_void) -> c_int;
    fn pcre_get_stringnumber(code: *Pcre, name: *c_char) -> c_int;
}

pub trait PatternUtil {
    pure fn info_capture_count(self) -> uint;
    pure fn info_name_count(self) -> uint;
    pure fn info_name_entry_size(self) -> uint;
    fn with_name_table(self, blk: fn(*u8));
    pure fn group_count(self) -> uint;
    pure fn group_names(self) -> ~[~str];
}

impl Pattern: PatternUtil {
    pure fn info_capture_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_CAPTURECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert count >= 0 as c_int;
        return count as uint;
    }

    pure fn info_name_count(self) -> uint {
        let count = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMECOUNT as c_int,
                                ptr::addr_of(&count) as *c_void);
        }
        assert count >= 0 as c_int;
        return count as uint;
    }

    pure fn info_name_entry_size(self) -> uint {
        let size = -1 as c_int;
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMEENTRYSIZE as c_int,
                                ptr::addr_of(&size) as *c_void);
        }
        assert size >= 0 as c_int;
        return size as uint;
    }

    fn with_name_table(self, blk: fn(*u8)) {
        let table = ptr::null::<u8>();
        unsafe {
            pcre::pcre_fullinfo(self.pcre_res.p, ptr::null(),
                                PCRE_INFO_NAMETABLE as c_int,
                                ptr::addr_of(&table) as *c_void);
        }
        assert table != ptr::null::<u8>();
        blk(table);
    }

    pure fn group_count(self) -> uint {
        return self.info_capture_count();
    }

    pure fn group_names(self) -> ~[~str] {
        let count = self.info_name_count();
        if count == 0u { return ~[]; }
        let size = self.info_name_entry_size();
        let mut names: ~[~str] = ~[];
        unsafe {
            do self.with_name_table |table| {
                for uint::range(0u, count) |i| {
                    let p = ptr::offset(table, size * i + 2u);
                    let s = str::raw::from_c_str(p as *c_char);
                    vec::push(&mut names, s);
                }
            }
        }
        return names;
    }
}

pub trait PatternLike {
    pure fn compile(&self, options: int) -> CompileResult;
}

impl &str: PatternLike {
    pure fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl ~str: PatternLike {
    pure fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl @str: PatternLike {
    pure fn compile(&self, options: int) -> CompileResult {
        compile(*self, options)
    }
}

impl Pattern: PatternLike {
    pure fn compile(&self, _options: int) -> CompileResult {
        Ok(*self)
    }
}

impl CompileResult: PatternLike {
    pure fn compile(&self, _options: int) -> CompileResult {
        *self
    }
}

pub trait MatchExtensions {
    pure fn matched(self) -> ~str;
    pure fn prematch(self) -> ~str;
    pure fn postmatch(self) -> ~str;
    pure fn begin(self) -> uint;
    pure fn end(self) -> uint;
    pure fn group(self, i: uint) -> Option<@~str>;
    pure fn named_group(self, name: &str) -> Option<@~str>;
    pure fn subgroups(self) -> ~[~str];
    fn subgroups_iter(self, blk: fn(&str));
    pure fn group_count(self) -> uint;
    pure fn group_names(self) -> ~[~str];
}

impl Match: MatchExtensions {
    pure fn matched(self) -> ~str {
        return str::slice(*self.subject, self.begin(), self.end());
    }

    pure fn prematch(self) -> ~str {
        return str::slice(*self.subject, 0u, self.begin());
    }

    pure fn postmatch(self) -> ~str {
        return str::slice(*self.subject ,self.end(),
                          str::char_len(*self.subject));
    }

    pure fn begin(self) -> uint {
        return self.captures[0] as uint;
    }

    pure fn end(self) -> uint {
        return self.captures[1] as uint;
    }

    pure fn group(self, i: uint) -> Option<@~str> {
        if i > self.group_count() {
            return None;
        }
        let i1 = self.captures[i * 2u];
        let i2 = self.captures[i * 2u + 1u];
        if(i1 < 0 || i2 < 0) {
            return None;
        }
        return Some(@str::slice(*self.subject, i1 as uint, i2 as uint));
    }

    pure fn named_group(self, name: &str) -> Option<@~str> {
        let i =  unsafe {
            str::as_buf(name, |s, _n| {
                pcre::pcre_get_stringnumber(self.pattern.pcre_res.p,
                                            s as *c_char)
            })
        };
        if i <= 0 as c_int { return None; }
        return self.group(i as uint);
    }

    pure fn subgroups(self) -> ~[~str] {
        let mut v = ~[];
        unsafe {
            vec::reserve(&mut v, self.group_count());
            do self.subgroups_iter |subgroup| {
                vec::push(&mut v, str::from_slice(subgroup));
            }
        }
        return v;
    }

    fn subgroups_iter(self, blk: fn(&str)) {
        for uint::range(1u, self.group_count() + 1u) |i| {
            match self.group(i) {
              Some(s) => blk(*s),
              None => die!(),
            }
        }
    }

    pure fn group_count(self) -> uint {
        return vec::len(*self.captures) / 2u - 1u;
    }

    pure fn group_names(self) -> ~[~str] {
        return self.pattern.group_names();
    }
}

pub pure fn compile(pattern: &str, options: int) -> CompileResult {
    if options | COMPILE_OPTIONS != COMPILE_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid
    let errcode = 0 as c_int;
    let errreason: *c_char = ptr::null();
    let erroffset = 0 as c_int;
    let p = unsafe {
        str::as_buf(pattern, |pat, _n| {
            pcre::pcre_compile2(pat as *c_char,
                                options as c_int,
                                ptr::addr_of(&errcode),
                                ptr::addr_of(&errreason),
                                ptr::addr_of(&erroffset),
                                ptr::null())
        })
    };
    if p == ptr::null() {
        let reason = unsafe { @str::raw::from_c_str(errreason) };
        return Err(CompileErr {code: errcode as int,
                               reason: reason,
                               offset: erroffset as uint});
    }
    return Ok(Pattern {str: @str::from_slice(pattern),
                       pcre_res: @PcreRes {p: p}});
}

pub pure fn exec(pattern: Pattern,
                 subject: &str, offset: uint,
                 options: int) -> ExecResult {

    if (options | EXEC_OPTIONS) != EXEC_OPTIONS {
        warn!("unrecognized option bit(s) are set");
    }

    let options = options | PCRE_NO_UTF8_CHECK; // str is always valid

    let count = (pattern.info_capture_count() + 1u) as c_int;
    let mut ovec = vec::from_elem((count as uint) * 3u, 0u as c_int);

    let ret_code = unsafe {
        str::as_buf(subject, |s, _n| {
            pcre::pcre_exec(pattern.pcre_res.p, ptr::null(),
                            s as *c_char, str::len(subject) as c_int,
                            offset as c_int, options as c_int,
                            vec::raw::to_ptr(ovec) as *c_int,
                            count * (3 as c_int)) as int
        })
    };

    if ret_code < 0 { return Err(ret_code as ExecErr); }

    // Truncate the working space.
    unsafe { vec::raw::set_len(&mut ovec, count as uint * 2u) }

    let mut captures: ~[int] = ~[];
    unsafe { vec::reserve(&mut captures, vec::len(ovec)); }
    for ovec.each |o| {
        unsafe { vec::push(&mut captures, *o as int); }
    }
    assert vec::len(captures) % 2u == 0u;

    return Ok(Match {subject: @str::from_slice(subject),
                     pattern: pattern,
                     captures: @captures});
}

pub pure fn search<T: PatternLike>(pattern: T, subject: &str,
                                   options: int)
                                   -> SearchResult {
    return search_from(pattern, subject, 0u, options);
}

pub pure fn search_from<T: PatternLike>(pattern: T, subject: &str,
                                        offset: uint, options: int)
                                        -> SearchResult {
    assert offset <= str::len(subject);

    let c_opts = options & COMPILE_OPTIONS;
    let e_opts = options & EXEC_OPTIONS;

    let c = pattern.compile(c_opts);
    match c {
        Ok(pattern) => {
            let e = exec(pattern, subject, offset, e_opts);
            match e {
                Ok(m) => {
                    return Ok(m);
                }
                Err(e_err) => {
                    return Err(ExecErr(e_err));
                }
            }
        }
        Err(c_err) => {
            return Err(CompileErr(c_err));
        }
    }
}

pub pure fn replace<T: PatternLike Copy>(pattern: T, subject: &str,
                                         repl: &str, options: int)
                                         -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, 0u, options);
}

pub pure fn replace_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                              repl: &str,  offset: uint,
                                              options: int)
                                              -> ReplaceResult {
    return replace_fn_from(pattern, subject,
                           |_m| { str::from_slice(repl) }, offset, options);
}

pub pure fn replace_fn<T: PatternLike Copy>(pattern: T, subject: &str,
                                            repl_fn: fn(Match) -> ~str,
                                            options: int)
                                            -> ReplaceResult {
    return replace_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub pure fn replace_fn_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                            repl_fn: fn(Match) -> ~str,
                                            offset: uint,
                                            options: int)
                                            -> ReplaceResult {
    let r = search_from(pattern, subject, offset, options);
    match r {
        Ok(m) => {
            return Ok(@(m.prematch() + repl_fn(m) + m.postmatch()));
        }
        Err(e) => { return Err(e); }
    }
}

pub pure fn replace_all<T: PatternLike Copy>(pattern: T, subject: &str,
                                             repl: &str,
                                             options: int)
                                             -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, 0u, options);
}

pub pure fn replace_all_fn<T: PatternLike Copy>(pattern: T, subject: &str,
                                                repl_fn: fn(Match) -> ~str,
                                                options: int)
                                                -> ReplaceResult {
    return replace_all_fn_from(pattern, subject, repl_fn, 0u, options);
}

pub pure fn replace_all_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                                  repl: &str,
                                                  offset: uint,
                                                  options: int)
                                                  -> ReplaceResult {
    return replace_all_fn_from(pattern, subject,
                               |_m| { str::from_slice(repl) }, offset, options);
}

pub pure fn replace_all_fn_from<T: PatternLike Copy>(pattern: T, subject: &str,
                                                     repl_fn: fn(Match) -> ~str,
                                                     offset: uint,
                                                     options: int)
                                                     -> ReplaceResult {
    let mut offset = offset;
    let subject_len = str::len(subject);
    assert offset <= subject_len;

    let mut s = str::slice(subject, 0, offset);
    loop {
        let r = search_from(pattern, subject, offset, options);
        match r {
            Ok(m) => {
                s += str::slice(subject, offset, m.begin());
                s += repl_fn(m);
                offset = m.end();
            }
            Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => {
                if offset != subject_len {
                    s += str::slice(subject, offset, subject_len);
                }
                break;
            }
            Err(e) => {
                return Err(copy e);
            }
        }
    }
    return Ok(@s);
}

pub pure fn fmt_compile_err(e: CompileErr) -> ~str {
    return fmt!("error %d: %s at offset %u", e.code, *e.reason, e.offset);
}

/// Return true iff `sr` indicates that the subject did not match the pattern
pub pure fn is_nomatch(sr: SearchResult) -> bool {
    match sr {
        Err(ExecErr(e)) if e == PCRE_ERROR_NOMATCH => true,
        _ => false,
    }
}
<|endoftext|>


<commit_before>extern crate lisp;

use lisp::toplevel;
use std::process;

fn main() {
    if let Err(e) = toplevel::repl() {
        println!("Error: {}", e);
        process::exit(1);
    }
}
<commit_msg>lisp: Run scheme files specified on command line<commit_after>extern crate cell_gc;
extern crate lisp;

use lisp::toplevel;
use std::env;
use std::fs;
use std::io::{self, Read};
use std::process;

fn main() {
    if let Err(e) = try_main() {
        println!("Error: {}", e);
        process::exit(1);
    }
}

fn try_main() -> io::Result<()> {
    if env::args().count() == 1 {
        return toplevel::repl();
    }

    cell_gc::with_heap(|hs| {
        let env = toplevel::default_env(hs);

        let mut source = String::new();
        for file in env::args().skip(1) {
            let mut file = fs::File::open(file)?;
            file.read_to_string(&mut source)?;

            if let Err(e) = toplevel::eval_str(hs, &env, &source) {
                return Err(io::Error::new(io::ErrorKind::Other, e.to_string()));
            }
            source.clear();
        }

        Ok(())
    })
}
<|endoftext|>


<commit_before>use crate::prelude::*;

/// The `SelectionBehaviorState` handles the `SelectionBehavior` widget.
#[derive(Default, AsAny)]
pub struct SelectionBehaviorState {
    toggle_selection: bool,
}

impl SelectionBehaviorState {
    fn toggle_selection(&mut self) {
        self.toggle_selection = true;
    }
}

impl State for SelectionBehaviorState {
    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        if !ctx.widget().get::<bool>("enabled") || !self.toggle_selection {
            return;
        }

        self.toggle_selection = false;

        let selected = *ctx.widget().get::<bool>("selected");
        ctx.widget().set("selected", !selected);

        let target: Entity = (*ctx.widget().get::<u32>("target")).into();
        ctx.push_event_strategy_by_entity(ChangedEvent(target), target, EventStrategy::Direct);
        ctx.get_widget(target).update_theme_by_state(false);
    }
}

widget!(
    /// The `SelectionBehavior` widget is used to handle internal the pressed behavior of a widget.
    ///
    /// **CSS element:** `check-box`
    SelectionBehavior<SelectionBehaviorState>: MouseHandler {
        /// Sets or shares the target of the behavior.
        target: u32,

        /// Sets or shares the selected property.
        selected: bool,

        /// Sets the parent id.
        parent: u32
    }
);

impl Template for SelectionBehavior {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("SelectionBehavior")
            .selected(true)
            .on_click(move |states, _| {
                states
                    .get_mut::<SelectionBehaviorState>(id)
                    .toggle_selection();
                false
            })
    }
}
<commit_msg>Fix selection behavior.<commit_after>use crate::prelude::*;

/// The `SelectionBehaviorState` handles the `SelectionBehavior` widget.
#[derive(Default, AsAny)]
pub struct SelectionBehaviorState {
    toggle_selection: bool,
    selected: bool
}

impl SelectionBehaviorState {
    fn toggle_selection(&mut self) {
        self.toggle_selection = true;
    }
}

impl State for SelectionBehaviorState {
    fn init(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        self.selected = *ctx.widget().get::<bool>("selected");
    }

    fn update(&mut self, _: &mut Registry, ctx: &mut Context<'_>) {
        let selected = *ctx.widget().get::<bool>("selected");

        if self.selected == selected && !self.toggle_selection {
            return;
        }

        if *ctx.widget().get::<bool>("enabled") && self.toggle_selection {
            ctx.widget().set("selected", !selected);
        }

        self.toggle_selection = false;
        self.selected = *ctx.widget().get::<bool>("selected");

        let target: Entity = (*ctx.widget().get::<u32>("target")).into();
        ctx.push_event_strategy_by_entity(ChangedEvent(target), target, EventStrategy::Direct);
        ctx.get_widget(target).update_theme_by_state(false);
    }
}

widget!(
    /// The `SelectionBehavior` widget is used to handle internal the pressed behavior of a widget.
    ///
    /// **CSS element:** `check-box`
    SelectionBehavior<SelectionBehaviorState>: MouseHandler {
        /// Sets or shares the target of the behavior.
        target: u32,

        /// Sets or shares the selected property.
        selected: bool,

        /// Sets the parent id.
        parent: u32
    }
);

impl Template for SelectionBehavior {
    fn template(self, id: Entity, _: &mut BuildContext) -> Self {
        self.name("SelectionBehavior")
            .selected(true)
            .on_click(move |states, _| {
                states
                    .get_mut::<SelectionBehaviorState>(id)
                    .toggle_selection();
                false
            })
    }
}
<|endoftext|>


<commit_before>use alloc::boxed::Box;

use core::ptr;
use core::sync::atomic::AtomicPtr;

pub use core::sync::atomic::Ordering;

pub struct Atomic<T> {
    ptr: AtomicPtr<T>,
}

unsafe impl<T> Send for Atomic<T> {}
unsafe impl<T> Sync for Atomic<T> {}

impl<T: Default> Default for Atomic<T> {

    #[inline(always)]
    fn default() -> Atomic<T> {
        Atomic::new(T::default())
    }
}

impl<T> Atomic<T> {

    #[inline(always)]
    pub fn new(value: T) -> Atomic<T> {
        Atomic {
            ptr: AtomicPtr::new(Box::into_raw(Box::new(value))),
        }
    }

    #[inline(always)]
    pub fn as_ptr(&self, order: Ordering) -> *mut T {
        self.ptr.load(order)
    }
    #[inline(always)]
    pub fn as_ref(&self, order: Ordering) -> &T {
        unsafe {
            &*self.as_ptr(order)
        }
    }
    #[inline(always)]
    pub fn as_mut(&mut self, order: Ordering) -> &mut T {
        unsafe {
            &mut *self.as_ptr(order)
        }
    }

    #[inline(always)]
    pub fn swap(&self, value: T, order: Ordering) -> T {
        unsafe {
            let ptr = Box::into_raw(Box::new(value));
            let old_ptr = self.ptr.swap(ptr, order);
            let old_value = ptr::read(old_ptr);
            Box::from_raw(old_ptr);
            old_value
        }
    }
    #[inline(always)]
    pub fn store(&self, value: T, order: Ordering)  {
        self.swap(value, order);
    }
}

#[cfg(test)]
mod test {
    use super::*;

    struct Foo {
        bar: usize,
    }

    impl Foo {
        fn new(bar: usize) -> Self {
            Foo {
                bar: bar,
            }
        }
    }

    #[test]
    fn as_ref_test() {
        let value = Atomic::new(Foo::new(0));
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 0);
    }
    #[test]
    fn as_mut_test() {
        let mut value = Atomic::new(Foo::new(0));
        value.as_mut(Ordering::Relaxed).bar = 1;
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 1);
    }
    #[test]
    fn swap_test() {
        let value = Atomic::new(Foo::new(0));
        let old_value = value.swap(Foo::new(1), Ordering::Relaxed);
        assert_eq!(old_value.bar, 0);
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 1);
    }

    #[test]
    fn threads() {
        use std::time;
        use std::thread;
        use std::vec::Vec;
        use alloc::arc::Arc;
        use core::sync::atomic::AtomicUsize;

        use prng::{AtomicPrng, MAX};

        static SIZE: usize = 32;

        let value = Arc::new(Atomic::new(Foo::new(0)));
        let count = Arc::new(AtomicUsize::new(0));
        let mut handles = Vec::new();
        let rand = Arc::new(AtomicPrng::new());

        for _ in 0..SIZE {
            let count = count.clone();
            let value = value.clone();
            let rand = rand.clone();

            handles.push(thread::spawn(move || {
                let ms = time::Duration::from_millis(((rand.next() as f64 / MAX as f64) * 128_f64) as u64);
                thread::sleep(ms);

                count.fetch_add(1, Ordering::Relaxed);

                let ms = time::Duration::from_millis(((rand.next() as f64 / MAX as f64) * 128_f64) as u64);
                thread::sleep(ms);

                value.swap(Foo::new(count.load(Ordering::Relaxed)), Ordering::Relaxed);
            }));
        }

        for handle in handles {
            let _ = handle.join();
        }

        assert_eq!((*value).as_ref(Ordering::Relaxed).bar, SIZE);
    }
}
<commit_msg>clean up, fix drop bug<commit_after>use alloc::boxed::Box;

use core::sync::atomic::AtomicPtr;

pub use core::sync::atomic::Ordering;

pub struct Atomic<T> {
    ptr: AtomicPtr<T>,
}

unsafe impl<T> Send for Atomic<T> {}
unsafe impl<T> Sync for Atomic<T> {}

impl<T: Default> Default for Atomic<T> {

    #[inline(always)]
    fn default() -> Atomic<T> {
        Atomic::new(T::default())
    }
}

impl<T> Atomic<T> {

    #[inline(always)]
    pub fn new(value: T) -> Atomic<T> {
        Atomic {
            ptr: AtomicPtr::new(Box::into_raw(Box::new(value))),
        }
    }

    #[inline(always)]
    fn as_ptr(&self, order: Ordering) -> *mut T {
        self.ptr.load(order)
    }
    #[inline(always)]
    pub fn as_ref(&self, order: Ordering) -> &T {
        unsafe {
            &*self.as_ptr(order)
        }
    }
    #[inline(always)]
    pub fn as_mut(&mut self, order: Ordering) -> &mut T {
        unsafe {
            &mut *self.as_ptr(order)
        }
    }

    #[inline(always)]
    pub fn swap(&self, value: T, order: Ordering) -> T {
        unsafe {
            let ptr = Box::into_raw(Box::new(value));
            let old_ptr = self.ptr.swap(ptr, order);
            *Box::from_raw(old_ptr)
        }
    }
    #[inline(always)]
    pub fn store(&self, value: T, order: Ordering)  {
        self.swap(value, order);
    }
}

#[cfg(test)]
mod test {
    use super::*;

    struct Foo {
        bar: usize,
    }

    impl Foo {
        fn new(bar: usize) -> Self {
            Foo {
                bar: bar,
            }
        }
    }

    #[test]
    fn as_ref_test() {
        let value = Atomic::new(Foo::new(0));
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 0);
    }
    #[test]
    fn as_mut_test() {
        let mut value = Atomic::new(Foo::new(0));
        value.as_mut(Ordering::Relaxed).bar = 1;
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 1);
    }
    #[test]
    fn swap_test() {
        let value = Atomic::new(Foo::new(0));
        let old_value = value.swap(Foo::new(1), Ordering::Relaxed);
        assert_eq!(old_value.bar, 0);
        assert_eq!(value.as_ref(Ordering::Relaxed).bar, 1);
    }

    #[test]
    fn drop_test() {
        static mut DROPPED: bool = false;

        struct DroppableFoo {
            bar: usize,
        }

        impl DroppableFoo {
            fn new(bar: usize) -> Self {
                DroppableFoo {
                    bar: bar,
                }
            }
        }

        impl Drop for DroppableFoo {
            fn drop(&mut self) {
                unsafe {
                    DROPPED = true;
                }
            }
        }

        {
            assert_eq!(unsafe {DROPPED}, false);

            let value = Atomic::new(DroppableFoo::new(0));
            let old_value = value.swap(DroppableFoo::new(1), Ordering::Relaxed);

            assert_eq!(unsafe {DROPPED}, false);

            assert_eq!(old_value.bar, 0);
            assert_eq!(value.as_ref(Ordering::Relaxed).bar, 1);
        }

        assert_eq!(unsafe {DROPPED}, true);
    }

    #[test]
    fn threads() {
        use std::time;
        use std::thread;
        use std::vec::Vec;
        use alloc::arc::Arc;
        use core::sync::atomic::AtomicUsize;

        use prng::{AtomicPrng, MAX};

        static SIZE: usize = 32;

        let value = Arc::new(Atomic::new(Foo::new(0)));
        let count = Arc::new(AtomicUsize::new(0));
        let mut handles = Vec::new();
        let rand = Arc::new(AtomicPrng::new());

        for _ in 0..SIZE {
            let count = count.clone();
            let value = value.clone();
            let rand = rand.clone();

            handles.push(thread::spawn(move || {
                let ms = time::Duration::from_millis(((rand.next() as f64 / MAX as f64) * 128_f64) as u64);
                thread::sleep(ms);

                count.fetch_add(1, Ordering::Relaxed);

                let ms = time::Duration::from_millis(((rand.next() as f64 / MAX as f64) * 128_f64) as u64);
                thread::sleep(ms);

                value.swap(Foo::new(count.load(Ordering::Relaxed)), Ordering::Relaxed);
            }));
        }

        for handle in handles {
            let _ = handle.join();
        }

        assert_eq!((*value).as_ref(Ordering::Relaxed).bar, SIZE);
    }
}
<|endoftext|>


<commit_before>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> &mut Room {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        self.room_from_matrix(&room_id.unwrap())
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream().get_ref(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg).unwrap();
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                self.handle_matrix(e);
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                let room = self.room_from_irc(&message.args[0]);
                                matrix::events::EventData::Room(
                                    room.id.clone(),
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<commit_msg>bridge: if a user sends to a room we're not in, don't catch on fire<commit_after>use irc;
use matrix;
use irc::protocol::{Command,Message};
use mio;
use mio::{EventLoop,Handler,Token,EventSet,PollOpt,Sender};
use std::thread;
use std::collections::HashMap;

const CLIENT: Token = Token(0);

#[derive(Debug)]
pub enum Event {
    EndPoll,
    Matrix(matrix::events::Event)
}

pub struct Bridge {
    client: irc::streams::Client,
    matrix: matrix::client::Client,
    rooms: HashMap<matrix::events::RoomID, Room>,
    seen_events: Vec<matrix::events::EventID>,
}

impl Handler for Bridge {
    type Timeout = ();
    type Message = Event;

    fn ready(&mut self, event_loop: &mut EventLoop<Bridge>, token: Token, _: EventSet) {
        match token {
            CLIENT =>
                self.handle_client(event_loop),
            _ => unreachable!()
        }
    }

    fn notify(&mut self, event_loop: &mut EventLoop<Bridge>, msg: Self::Message) {
        match msg {
            Event::EndPoll => {
                self.poll_matrix(event_loop.channel());
            },
            Event::Matrix(e) =>
                self.handle_matrix(e)
        };
    }
}

unsafe impl Sync for Bridge{}

struct Room {
    id: matrix::events::RoomID,
    canonical_alias: Option<String>,
    join_rules: Option<String>,
    members: Vec<matrix::events::UserID>,
    pending_events: Vec<matrix::events::RoomEvent>
}

impl Room {
    fn new(id: matrix::events::RoomID) -> Self {
        Room {
            id: id,
            canonical_alias: None,
            join_rules: None,
            members: vec![],
            pending_events: vec![]
        }
    }

    fn run_pending<F>(&mut self, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        while let Some(evt) = self.pending_events.pop() {
            self.handle_with_alias(evt, callback);
        }
    }

    fn handle_with_alias<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: &mut F)
            where F: FnMut(irc::protocol::Message) {
        if self.canonical_alias != None {
            match evt {
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Join) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Join,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(user, matrix::events::MembershipAction::Leave) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Part,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: None
                    });
                    self.members.push(user);
                },
                matrix::events::RoomEvent::Membership(_, _) => (),
                matrix::events::RoomEvent::Message(user, text) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Privmsg,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(text)
                    });
                },
                matrix::events::RoomEvent::Topic(user, topic) => {
                    callback(irc::protocol::Message {
                        prefix: Some(format!("{}!{}@{}", user.nickname, user.nickname, user.homeserver)),
                        command: irc::protocol::Command::Topic,
                        args: vec![self.canonical_alias.clone().unwrap()],
                        suffix: Some(topic.clone())
                    });
                },
                matrix::events::RoomEvent::CanonicalAlias(_) => unreachable!(),
                _ => {
                    warn!("Unhandled event {:?}", evt)
                }
            }
        } else {
            self.pending_events.push(evt);
        }
    }

    fn handle_event<F>(&mut self, evt: matrix::events::RoomEvent, mut callback: F)
            where F: FnMut(irc::protocol::Message) {
        match evt {
            matrix::events::RoomEvent::CanonicalAlias(name) => {
                let was_empty = self.canonical_alias == None;
                self.canonical_alias = Some(name.clone());
                if was_empty {
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::JoinRules(rules) =>
                self.join_rules = Some(rules.clone()),
            matrix::events::RoomEvent::Create => (),
            matrix::events::RoomEvent::Aliases(aliases) => {
                let is_empty = self.canonical_alias == None;
                if is_empty {
                    self.canonical_alias = Some(aliases[0].clone());
                    self.run_pending(&mut callback);
                }
            },
            matrix::events::RoomEvent::PowerLevels => (),
            matrix::events::RoomEvent::HistoryVisibility(_) => (),
            matrix::events::RoomEvent::Name(_, _) => (),
            matrix::events::RoomEvent::Avatar(_, _) => (),
            matrix::events::RoomEvent::Unknown(unknown_type, json) => {
                warn!("Unknown room event {}", unknown_type);
                trace!("raw event: {:?}", json);
            }
            _ => self.handle_with_alias(evt, &mut callback)
        };
    }
}

impl Bridge {
    pub fn room_from_matrix(&mut self, id: &matrix::events::RoomID) -> &mut Room {
        if !self.rooms.contains_key(id) {
            self.rooms.insert(id.clone(), Room::new(id.clone()));
        }
        match self.rooms.get_mut(id) {
            Some(room) => room,
            None => unreachable!()
        }
    }

    pub fn room_from_irc(&mut self, id: &String) -> Option<&mut Room> {
        let mut room_id: Option<matrix::events::RoomID> = None;
        for (_, r) in self.rooms.iter_mut() {
            if let Some(ref alias) = r.canonical_alias {
                if alias == id {
                    room_id = Some(r.id.clone())
                }
            }
        }
        match room_id {
            Some(id) => Some(self.room_from_matrix(&id)),
            None => None
        }
    }

    pub fn new(client: irc::streams::Client, url: &str) -> Self {
        Bridge {
            client: client,
            matrix: matrix::client::Client::new(url),
            rooms: HashMap::new(),
            seen_events: vec![]
        }
    }

    pub fn run(&mut self) {
        let mut events = EventLoop::new().unwrap();
        events.register(self.client.stream().get_ref(), CLIENT, EventSet::all(), PollOpt::edge()).unwrap();
        events.run(self).unwrap();
    }

    fn handle_matrix(&mut self, evt: matrix::events::Event) {
        let duplicate = match evt.id {
            Some(ref id) =>
                self.seen_events.contains(id),
            _ => false
        };
        if !duplicate {
            let mut messages: Vec<irc::protocol::Message> = vec![];
            {
                let append_msg = |msg: irc::protocol::Message| {
                    messages.push(msg);
                };
                match evt.data {
                    matrix::events::EventData::Room(room_id, room_event) => {
                        self.room_from_matrix(&room_id).handle_event(room_event, append_msg);
                    },
                    matrix::events::EventData::Typing(_) => (),
                    _ => warn!("Unhandled {}", evt.data.type_str())
                }
            }
            match evt.id {
                Some(id) =>
                    self.seen_events.push(id),
                None => ()
            };
            for ref msg in messages {
                self.client.send(msg).unwrap();
            }
        }
    }

    fn poll_matrix(&mut self, channel: mio::Sender<Event>) ->
        thread::JoinHandle<matrix::client::Result> {
        let poll = self.matrix.poll_async();
        thread::spawn(move|| {
            poll.send().and_then(|evts| {
                for evt in evts {
                    channel.send(Event::Matrix(evt)).unwrap();
                };
                channel.send(Event::EndPoll).unwrap();
                Ok(())
            })
        })
    }

    fn start_matrix(&mut self, channel: mio::Sender<Event>) ->
        matrix::client::Result {
        self.matrix.sync().and_then(|events| {
            for e in events {
                self.handle_matrix(e);
            }
            self.poll_matrix(channel);
            Ok(())
        })
    }

    fn handle_client(&mut self, events: &mut EventLoop<Bridge>) {
        loop {
            match self.client.read_message() {
                None => return,
                Some(message) => {
                    match message.command {
                        Command::Pass => {
                            self.client.auth.set_password(message.args[0].clone())
                        }
                        Command::Nick => {
                            self.client.set_nickname(message.args[0].clone());
                        },
                        Command::User => {
                            self.client.auth.set_username(message.args[0].clone());
                            let auth = self.client.auth.consume();
                            match (auth.username, auth.password) {
                                (Some(username), Some(password)) => {
                                    self.matrix.login(username.trim(), password.trim())
                                        .and_then(|_| {
                                            self.start_matrix(events.channel())
                                        })
                                        .and_then(|_| {
                                            self.client.welcome(username.trim()).unwrap();
                                            debug!("Logged in a user");
                                            Ok(())
                                        }).expect("Could not login!");
                                },
                                _ => panic!("Username and/or password missing")
                            };
                        },
                        Command::Join => {
                            self.client.join(&message.args[0]).expect("Could not send JOIN");
                        },
                        Command::Ping => {
                            self.client.pong().expect("Could not send PONG");
                        },
                        Command::Quit => {
                            // FIXME: Logout of matrix and exit thread
                            return;
                        },
                        Command::Privmsg => {
                            let room_id = match self.room_from_irc(&message.args[0]) {
                                None => return (),
                                Some(room) => room.id.clone()
                            };
                            let evt = {
                                let id = self.matrix.uid.clone().unwrap();
                                matrix::events::EventData::Room(
                                    room_id,
                                    matrix::events::RoomEvent::Message(
                                        id, message.suffix.unwrap()))
                            };
                            self.seen_events.push(self.matrix.send(evt).expect("Could not send event"));
                        },
                        _ =>
                            warn!("unhandled {:?}", message)
                    }
                }
            }
        }
    }
}

<|endoftext|>


<commit_before>use arraymap::ArrayMap;
use itertools::Itertools;
use mli::*;
use mli_ndarray::Ndeep;
use ndarray::{Array, Array1, Array2, OwnedRepr};

type D1 = ndarray::Ix1;

fn corners(coordinate: [f32; 2]) -> [[isize; 2]; 4] {
    let c00 = coordinate.map(|f| f.floor() as isize);
    let c11 = coordinate.map(|f| f.ceil() as isize);
    let c01 = [c00[0], c11[1]];
    let c10 = [c11[0], c00[1]];
    [c00, c01, c10, c11]
}

/// Looks up a position gradient from a location in the features using bilinear interpolation and zero-padding.
fn bilinear_position_gradient(f: [f32; 4], rc: [f32; 2]) -> [f32; 2] {
    // Perform the y interpolation to get the x values.
    let fx = [
        (1.0 - rc[0]) * f[0] + rc[0] * f[2],
        (1.0 - rc[0]) * f[1] + rc[0] * f[3],
    ];

    // Perform the x interpolation to get the y values.
    let fy = [
        (1.0 - rc[1]) * f[0] + rc[1] * f[1],
        (1.0 - rc[1]) * f[2] + rc[1] * f[3],
    ];

    // The gradient is the difference between the interpolation values in each dimension.
    [fy[1] - fy[0], fx[1] - fx[0]]
}

pub struct DefConvData {
    pub offsets: Array2<f32>,
    pub features: Array2<f32>,
}

impl DefConvData {
    fn validate_corners(&self, coordinate: [f32; 2]) -> ([Option<[usize; 2]>; 4], [f32; 2]) {
        // Get the integer versions of four corners.
        let coords = corners(coordinate);

        // Get the relative coordinate.
        let rc = [
            coordinate[0] - coords[0][0] as f32,
            coordinate[1] - coords[0][1] as f32,
        ];

        // Create a closure to detect out-of-bounds.
        let in_bounds = |[y, x]: [isize; 2]| {
            if y < 0
                || x < 0
                || y >= self.features.shape()[0] as isize
                || x >= self.features.shape()[1] as isize
            {
                None
            } else {
                Some([y, x].map(|&n| n as usize))
            }
        };

        // Create a closure to extract the feature with zero-padding.
        let extract = |c| in_bounds(c);

        (coords.map(|&c| extract(c)), rc)
    }

    /// Extracts the corner features and relative coordinate for a bilinear interpolation.
    fn extract_corners(&self, validated_corners: [Option<[usize; 2]>; 4]) -> [f32; 4] {
        validated_corners.map(|c| c.as_ref().map(|&c| self.features[c]).unwrap_or(0.0))
    }

    /// Looks up a location in the features using bilinear interpolation and zero-padding.
    fn bilinear(&self, coordinate: [f32; 2]) -> f32 {
        // Extract the corner features and the relative coordinate.
        let (validated_corners, rc) = self.validate_corners(coordinate);
        let f = self.extract_corners(validated_corners);

        // Perform the y interpolation.
        let fx = [
            (1.0 - rc[0]) * f[0] + rc[0] * f[2],
            (1.0 - rc[0]) * f[1] + rc[0] * f[3],
        ];

        // Perform the x interpolation.
        (1.0 - rc[1]) * fx[0] + rc[1] * fx[1]
    }
}

#[derive(Clone, Debug)]
pub struct DefConv2 {
    weights: Array1<f32>,
    output_shape: [usize; 2],
}

impl DefConv2 {
    pub fn new(weights: Array1<f32>, output_shape: [usize; 2]) -> Self {
        Self {
            weights,
            output_shape,
        }
    }
}

impl Forward for DefConv2 {
    type Input = DefConvData;
    type Internal = ();
    type Output = Array2<f32>;

    fn forward(&self, input: &Self::Input) -> ((), Self::Output) {
        assert_eq!(self.weights.len(), input.offsets.shape()[0]);
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // Compute bilinear interpolation for (y, x) pairs.
        (
            (),
            Array::from_shape_vec(
                outshape,
                (0..outshape[0])
                    .cartesian_product(0..outshape[1])
                    .map(|(y, x)| {
                        self.weights
                            .iter()
                            .zip(input.offsets.outer_iter())
                            .map(|(weight, offset)| {
                                input.bilinear([
                                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                                ]) * weight
                            })
                            .sum()
                    })
                    .collect(),
            )
            .expect("mli-defconv: unexpected shape vec"),
        )
    }
}

impl Backward for DefConv2 {
    type OutputDelta = Array2<f32>;
    type InputDelta = DefConvData;
    type TrainDelta = Ndeep<OwnedRepr<f32>, D1>;

    fn backward(
        &self,
        input: &Self::Input,
        _: &Self::Internal,
        output_delta: &Self::OutputDelta,
    ) -> (Self::InputDelta, Self::TrainDelta) {
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // We cannot determine in advance what locations are affected
        let mut feature_deltas: Array2<f32> = Array2::zeros(inshape);
        let mut offset_deltas: Array2<f32> = Array2::zeros(input.offsets.raw_dim());
        let mut weight_deltas: Array1<f32> = Array1::zeros(self.weights.raw_dim());

        for (y, x) in (0..outshape[0]).cartesian_product(0..outshape[1]) {
            let output_delta = output_delta[[y, x]];
            for (ix, (weight, offset)) in self
                .weights
                .iter()
                .zip(input.offsets.outer_iter())
                .enumerate()
            {
                // Compute the original sample coordinate.
                let sample_coordinate = [
                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                ];

                // Find the corners if they are within the input.
                let (validated_corners, rc) = input.validate_corners(sample_coordinate);

                // Loop over all the corners and the amount each contributed.
                for (coord, coeff) in validated_corners.iter().zip(
                    [
                        (1.0 - rc[0]) * (1.0 - rc[1]),
                        (1.0 - rc[0]) * rc[1],
                        rc[0] * (1.0 - rc[1]),
                        rc[0] * rc[1],
                    ]
                    .iter(),
                ) {
                    // If the coordinate was in bounds of the input tensor.
                    if let Some(coord) = coord {
                        // Add the contribution.
                        feature_deltas[*coord] += coeff * weight * output_delta;
                    }
                }

                // Compute the position gradients.
                let f = input.extract_corners(validated_corners);
                let position_gradient = bilinear_position_gradient(f, rc);
                // Compute and add the offset gradients based on the position gradients and chain rule.
                // The multipliers affect the gradient of the position because they multiply the sampling locations.
                // The greater the weight the greater the effect on sampling location because the output is multiplied by the weight.
                offset_deltas[[ix, 0]] +=
                    multipliers[0] * position_gradient[0] * weight * output_delta;
                offset_deltas[[ix, 1]] +=
                    multipliers[1] * position_gradient[1] * weight * output_delta;

                // TODO: This is incredibly inefficient recomputing the entire bilinear interpolation. Use internals to store it.
                weight_deltas[ix] += input.bilinear(sample_coordinate) * output_delta;
            }
        }

        // Compute bilinear interpolation for (y, x) pairs.
        (
            DefConvData {
                features: feature_deltas,
                offsets: offset_deltas,
            },
            Ndeep(weight_deltas),
        )
    }
}
<commit_msg>change defconv to take tuples<commit_after>use arraymap::ArrayMap;
use itertools::Itertools;
use mli::*;
use mli_ndarray::Ndeep;
use ndarray::{Array, Array1, Array2, OwnedRepr};

type D1 = ndarray::Ix1;

fn corners(coordinate: [f32; 2]) -> [[isize; 2]; 4] {
    let c00 = coordinate.map(|f| f.floor() as isize);
    let c11 = coordinate.map(|f| f.ceil() as isize);
    let c01 = [c00[0], c11[1]];
    let c10 = [c11[0], c00[1]];
    [c00, c01, c10, c11]
}

/// Looks up a position gradient from a location in the features using bilinear interpolation and zero-padding.
fn bilinear_position_gradient(f: [f32; 4], rc: [f32; 2]) -> [f32; 2] {
    // Perform the y interpolation to get the x values.
    let fx = [
        (1.0 - rc[0]) * f[0] + rc[0] * f[2],
        (1.0 - rc[0]) * f[1] + rc[0] * f[3],
    ];

    // Perform the x interpolation to get the y values.
    let fy = [
        (1.0 - rc[1]) * f[0] + rc[1] * f[1],
        (1.0 - rc[1]) * f[2] + rc[1] * f[3],
    ];

    // The gradient is the difference between the interpolation values in each dimension.
    [fy[1] - fy[0], fx[1] - fx[0]]
}

pub struct DefConvData<'a> {
    pub features: &'a Array2<f32>,
    pub offsets: &'a Array2<f32>,
}

impl<'a> DefConvData<'a> {
    fn validate_corners(&self, coordinate: [f32; 2]) -> ([Option<[usize; 2]>; 4], [f32; 2]) {
        // Get the integer versions of four corners.
        let coords = corners(coordinate);

        // Get the relative coordinate.
        let rc = [
            coordinate[0] - coords[0][0] as f32,
            coordinate[1] - coords[0][1] as f32,
        ];

        // Create a closure to detect out-of-bounds.
        let in_bounds = |[y, x]: [isize; 2]| {
            if y < 0
                || x < 0
                || y >= self.features.shape()[0] as isize
                || x >= self.features.shape()[1] as isize
            {
                None
            } else {
                Some([y, x].map(|&n| n as usize))
            }
        };

        // Create a closure to extract the feature with zero-padding.
        let extract = |c| in_bounds(c);

        (coords.map(|&c| extract(c)), rc)
    }

    /// Extracts the corner features and relative coordinate for a bilinear interpolation.
    fn extract_corners(&self, validated_corners: [Option<[usize; 2]>; 4]) -> [f32; 4] {
        validated_corners.map(|c| c.as_ref().map(|&c| self.features[c]).unwrap_or(0.0))
    }

    /// Looks up a location in the features using bilinear interpolation and zero-padding.
    fn bilinear(&self, coordinate: [f32; 2]) -> f32 {
        // Extract the corner features and the relative coordinate.
        let (validated_corners, rc) = self.validate_corners(coordinate);
        let f = self.extract_corners(validated_corners);

        // Perform the y interpolation.
        let fx = [
            (1.0 - rc[0]) * f[0] + rc[0] * f[2],
            (1.0 - rc[0]) * f[1] + rc[0] * f[3],
        ];

        // Perform the x interpolation.
        (1.0 - rc[1]) * fx[0] + rc[1] * fx[1]
    }
}

#[derive(Clone, Debug)]
pub struct DefConv2 {
    weights: Array1<f32>,
    output_shape: [usize; 2],
}

impl DefConv2 {
    pub fn new(weights: Array1<f32>, output_shape: [usize; 2]) -> Self {
        Self {
            weights,
            output_shape,
        }
    }
}

impl Forward for DefConv2 {
    type Input = (Array2<f32>, Array2<f32>);
    type Internal = ();
    type Output = Array2<f32>;

    fn forward(&self, (features, offsets): &Self::Input) -> ((), Self::Output) {
        let input = DefConvData { features, offsets };
        assert_eq!(self.weights.len(), input.offsets.shape()[0]);
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // Compute bilinear interpolation for (y, x) pairs.
        (
            (),
            Array::from_shape_vec(
                outshape,
                (0..outshape[0])
                    .cartesian_product(0..outshape[1])
                    .map(|(y, x)| {
                        self.weights
                            .iter()
                            .zip(input.offsets.outer_iter())
                            .map(|(weight, offset)| {
                                input.bilinear([
                                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                                ]) * weight
                            })
                            .sum()
                    })
                    .collect(),
            )
            .expect("mli-defconv: unexpected shape vec"),
        )
    }
}

impl Backward for DefConv2 {
    type OutputDelta = Array2<f32>;
    type InputDelta = (Array2<f32>, Array2<f32>);
    type TrainDelta = Ndeep<OwnedRepr<f32>, D1>;

    fn backward(
        &self,
        (features, offsets): &Self::Input,
        _: &Self::Internal,
        output_delta: &Self::OutputDelta,
    ) -> (Self::InputDelta, Self::TrainDelta) {
        let input = DefConvData { features, offsets };
        // Get shapes.
        let outshape = self.output_shape;
        let inshape = input.features.raw_dim();

        // Compute the coordinate multiplier.
        let multipliers = [
            inshape[0] as f32 / outshape[0] as f32,
            inshape[1] as f32 / outshape[1] as f32,
        ];

        // We cannot determine in advance what locations are affected
        let mut feature_deltas: Array2<f32> = Array2::zeros(inshape);
        let mut offset_deltas: Array2<f32> = Array2::zeros(input.offsets.raw_dim());
        let mut weight_deltas: Array1<f32> = Array1::zeros(self.weights.raw_dim());

        for (y, x) in (0..outshape[0]).cartesian_product(0..outshape[1]) {
            let output_delta = output_delta[[y, x]];
            for (ix, (weight, offset)) in self
                .weights
                .iter()
                .zip(input.offsets.outer_iter())
                .enumerate()
            {
                // Compute the original sample coordinate.
                let sample_coordinate = [
                    (y as f32 + 0.5 + offset[0]) * multipliers[0],
                    (x as f32 + 0.5 + offset[1]) * multipliers[1],
                ];

                // Find the corners if they are within the input.
                let (validated_corners, rc) = input.validate_corners(sample_coordinate);

                // Loop over all the corners and the amount each contributed.
                for (coord, coeff) in validated_corners.iter().zip(
                    [
                        (1.0 - rc[0]) * (1.0 - rc[1]),
                        (1.0 - rc[0]) * rc[1],
                        rc[0] * (1.0 - rc[1]),
                        rc[0] * rc[1],
                    ]
                    .iter(),
                ) {
                    // If the coordinate was in bounds of the input tensor.
                    if let Some(coord) = coord {
                        // Add the contribution.
                        feature_deltas[*coord] += coeff * weight * output_delta;
                    }
                }

                // Compute the position gradients.
                let f = input.extract_corners(validated_corners);
                let position_gradient = bilinear_position_gradient(f, rc);
                // Compute and add the offset gradients based on the position gradients and chain rule.
                // The multipliers affect the gradient of the position because they multiply the sampling locations.
                // The greater the weight the greater the effect on sampling location because the output is multiplied by the weight.
                offset_deltas[[ix, 0]] +=
                    multipliers[0] * position_gradient[0] * weight * output_delta;
                offset_deltas[[ix, 1]] +=
                    multipliers[1] * position_gradient[1] * weight * output_delta;

                // TODO: This is incredibly inefficient recomputing the entire bilinear interpolation. Use internals to store it.
                weight_deltas[ix] += input.bilinear(sample_coordinate) * output_delta;
            }
        }

        // Compute bilinear interpolation for (y, x) pairs.
        ((feature_deltas, offset_deltas), Ndeep(weight_deltas))
    }
}
<|endoftext|>


<commit_before>#[allow(non_camel_case_types)]

use cgmath;
use cgmath::{vec3};
use cgmath::prelude::*;

type Point3 = cgmath::Point3<f32>;
type Vector3 = cgmath::Vector3<f32>;
type Matrix4 = cgmath::Matrix4<f32>;

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
pub enum Camera_Movement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
}

// Default camera values
const YAW: f32        = -90.0;
const PITCH: f32      =  0.0;
const SPEED: f32      =  2.5;
const SENSITIVTY: f32 =  0.1;
const ZOOM: f32       =  45.0;

struct Camera {
    // Camera Attributes
    pub Position: Vector3,
    pub Front: Vector3,
    pub Up: Vector3,
    pub Right: Vector3,
    pub WorldUp: Vector3,
    // Euler Angles
    pub Yaw: f32,
    pub Pitch: f32,
    // Camera options
    pub MovementSpeed: f32,
    pub MouseSensitivity: f32,
    pub Zoom: f32,
}

impl Camera {
    fn new(position: Vector3, up: Vector3, yaw: f32, pitch: f32) -> Camera {
        Camera {
            Position: position,
            WorldUp: up,
            Yaw: yaw,
            Pitch: pitch,
            ..Camera::default()
        }
    }

    fn updateCameraVectors(&mut self) {
        unimplemented!()
    }
}

impl Default for Camera {
    fn default() -> Camera {
        let mut camera = Camera {
            Position: Vector3::zero(),
            Front: vec3(0.0, 0.0, -1.0),
            Up: Vector3::zero(),        // initialized later
            Right: Vector3::zero(),     // initialized later
            WorldUp: Vector3::unit_y(),
            Yaw: YAW,
            Pitch: PITCH,
            MovementSpeed: SPEED,
            MouseSensitivity: SENSITIVTY,
            Zoom: ZOOM,
        };
        camera.updateCameraVectors();
        camera
    }
}
<commit_msg>camera: updateCameraVectors<commit_after>#![allow(non_camel_case_types)]
#![allow(non_snake_case)]

use cgmath;
use cgmath::{vec3};
use cgmath::prelude::*;

type Point3 = cgmath::Point3<f32>;
type Vector3 = cgmath::Vector3<f32>;
type Matrix4 = cgmath::Matrix4<f32>;

// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
pub enum Camera_Movement {
    FORWARD,
    BACKWARD,
    LEFT,
    RIGHT
}

// Default camera values
const YAW: f32        = -90.0;
const PITCH: f32      =  0.0;
const SPEED: f32      =  2.5;
const SENSITIVTY: f32 =  0.1;
const ZOOM: f32       =  45.0;

struct Camera {
    // Camera Attributes
    pub Position: Vector3,
    pub Front: Vector3,
    pub Up: Vector3,
    pub Right: Vector3,
    pub WorldUp: Vector3,
    // Euler Angles
    pub Yaw: f32,
    pub Pitch: f32,
    // Camera options
    pub MovementSpeed: f32,
    pub MouseSensitivity: f32,
    pub Zoom: f32,
}

impl Camera {
    fn new(position: Vector3, up: Vector3, yaw: f32, pitch: f32) -> Camera {
        Camera {
            Position: position,
            WorldUp: up,
            Yaw: yaw,
            Pitch: pitch,
            ..Camera::default()
        }
    }

    // TODO? constructor with scalar values

    /// Calculates the front vector from the Camera's (updated) Eular Angles
    fn updateCameraVectors(&mut self) {
        // Calculate the new Front vector
        let front = Vector3 {
            x: self.Yaw.to_radians().cos() * self.Pitch.to_radians().cos(),
            y: self.Pitch.to_radians().sin(),
            z: self.Yaw.to_radians().sin() * self.Pitch.to_radians().cos()
        };
        self.Front = front.normalize();
        // Also re-calculate the Right and Up vector
        self.Right = self.Front.cross(self.WorldUp).normalize(); // Normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
        self.Up = self.Right.cross(self.Front).normalize();
    }
}

impl Default for Camera {
    fn default() -> Camera {
        let mut camera = Camera {
            Position: Vector3::zero(),
            Front: vec3(0.0, 0.0, -1.0),
            Up: Vector3::zero(),        // initialized later
            Right: Vector3::zero(),     // initialized later
            WorldUp: Vector3::unit_y(),
            Yaw: YAW,
            Pitch: PITCH,
            MovementSpeed: SPEED,
            MouseSensitivity: SENSITIVTY,
            Zoom: ZOOM,
        };
        camera.updateCameraVectors();
        camera
    }
}
<|endoftext|>