<commit_before>use std::{
    fs::{self, File},
    io::{BufRead, BufReader},
    path::Path,
};

use crate::Result;

pub(crate) fn check_spec_links(path: &Path) -> Result<()> {
    println!("Checking Matrix Spec links are up-to-date...");
    walk_dirs(path, "https://matrix.org/docs/spec/", |_| false)?;
    walk_dirs(path, "https://spec.matrix.org/", |s| {
        s.starts_with("v1.2") || s.starts_with("unstable")
    })?;
    Ok(())
}

fn walk_dirs(path: &Path, split: &str, version_match: fn(&str) -> bool) -> Result<()> {
    if path.is_dir() {
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                walk_dirs(&path, split, version_match)?;
            } else {
                let mut buf = String::new();
                let mut content = BufReader::new(File::open(&path)?);

                // We can assume a spec link will never overflow to another line
                while content.read_line(&mut buf)? > 0 {
                    // If for some reason a line has 2 spec links
                    for (idx, _) in buf.match_indices(split) {
                        if !version_match(&buf[idx + split.len()..]) {
                            return err(&path, &buf);
                        }
                    }
                    buf.clear();
                }
            }
        }
    }
    Ok(())
}

fn err(path: &Path, snippet: &str) -> Result<()> {
    Err(format!(
        "error: spec URL with wrong version number\nfile: {}\n\nsnippet:\n{}",
        path.display(),
        &snippet[0..25]
    )
    .into())
}
<commit_msg>ci: Fix accidental ban of v1.1 spec links<commit_after>use std::{
    fs::{self, File},
    io::{BufRead, BufReader},
    path::Path,
};

use crate::Result;

pub(crate) fn check_spec_links(path: &Path) -> Result<()> {
    println!("Checking Matrix Spec links are up-to-date...");
    walk_dirs(path, "https://matrix.org/docs/spec/", |_| false)?;
    walk_dirs(path, "https://spec.matrix.org/", |s| {
        s.starts_with("v1.1") || s.starts_with("v1.2") || s.starts_with("unstable")
    })?;
    Ok(())
}

fn walk_dirs(path: &Path, split: &str, version_match: fn(&str) -> bool) -> Result<()> {
    if path.is_dir() {
        for entry in fs::read_dir(path)? {
            let entry = entry?;
            let path = entry.path();
            if path.is_dir() {
                walk_dirs(&path, split, version_match)?;
            } else {
                let mut buf = String::new();
                let mut content = BufReader::new(File::open(&path)?);

                // We can assume a spec link will never overflow to another line
                while content.read_line(&mut buf)? > 0 {
                    // If for some reason a line has 2 spec links
                    for (idx, _) in buf.match_indices(split) {
                        if !version_match(&buf[idx + split.len()..]) {
                            return err(&path, &buf);
                        }
                    }
                    buf.clear();
                }
            }
        }
    }
    Ok(())
}

fn err(path: &Path, snippet: &str) -> Result<()> {
    Err(format!(
        "error: spec URL with wrong version number\nfile: {}\n\nsnippet:\n{}",
        path.display(),
        &snippet[0..25]
    )
    .into())
}
<|endoftext|>


<commit_before>import os.libc;

native "rust" mod rustrt {
  fn rust_get_stdin() -> os.libc.FILE;
  fn rust_get_stdout() -> os.libc.FILE;
}

// Reading

// TODO This is all buffered. We might need an unbuffered variant as well

tag seek_style {seek_set; seek_end; seek_cur;}

type reader =
    state obj {
          impure fn read_byte() -> u8;
          impure fn read_bytes(uint len) -> vec[u8];
          impure fn read_char() -> int;
          impure fn unread_char(int i);
          impure fn eof() -> bool;
          impure fn read_line() -> str;
          impure fn read_c_str() -> str;
          impure fn read_le_uint(uint size) -> uint;
          impure fn read_le_int(uint size) -> int;

          impure fn seek(int offset, seek_style whence);
          impure fn tell() -> uint; // TODO: eventually u64
    };

fn convert_whence(seek_style whence) -> int {
    alt (whence) {
        case (seek_set) {ret 0;}
        case (seek_cur) {ret 1;}
        case (seek_end) {ret 2;}
    }
}

state obj FILE_reader(os.libc.FILE f, bool must_close) {
    impure fn read_byte() -> u8 {
        ret os.libc.fgetc(f) as u8;
    }
    impure fn read_bytes(uint len) -> vec[u8] {
        auto buf = _vec.alloc[u8](len);
        auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f);
        _vec.len_set[u8](buf, read);
        ret buf;
    }
    impure fn read_char() -> int {
        ret os.libc.fgetc(f);
    }
    impure fn unread_char(int ch) {
        os.libc.ungetc(ch, f);
    }
    impure fn eof() -> bool {
      auto ch = os.libc.fgetc(f);
      if (ch == -1) {ret true;}
      os.libc.ungetc(ch, f);
      ret false;
    }
    impure fn read_line() -> str {
      auto buf = "";
      while (true) {
        auto ch = os.libc.fgetc(f);
        if (ch == -1) { ret buf; }
        if (ch == 10) { ret buf; }
        buf += _str.unsafe_from_bytes(vec(ch as u8));
      }
      ret buf;
    }
    impure fn read_c_str() -> str {
        auto buf = "";
        while (true) {
            auto ch = os.libc.fgetc(f);
            if (ch < 1) { ret buf; }
            buf += _str.unsafe_from_bytes(vec(ch as u8));
        }
        ret buf;
    }
    // TODO deal with eof?
    impure fn read_le_uint(uint size) -> uint {
        auto val = 0u;
        auto pos = 0u;
        while (size > 0u) {
            val += (os.libc.fgetc(f) as uint) << pos;
            pos += 8u;
            size -= 1u;
        }
        ret val;
    }
    impure fn read_le_int(uint size) -> int {
        auto val = 0u;
        auto pos = 0u;
        while (size > 0u) {
            val += (os.libc.fgetc(f) as uint) << pos;
            pos += 8u;
            size -= 1u;
        }
        ret val as int; // TODO does that work?
    }
    impure fn seek(int offset, seek_style whence) {
        check(os.libc.fseek(f, offset, convert_whence(whence)) == 0);
    }
    impure fn tell() -> uint {
        ret os.libc.ftell(f) as uint;
    }
    drop {
        if (must_close) {os.libc.fclose(f);}
    }
}

fn stdin() -> reader {
    ret FILE_reader(rustrt.rust_get_stdin(), false);
}

fn file_reader(str path) -> reader {
    auto f = os.libc.fopen(_str.buf(path), _str.buf("r"));
    if (f as uint == 0u) {
        log "error opening " + path;
        fail;
    }
    ret FILE_reader(f, true);
}

// Writing

// TODO This is all unbuffered. We might need a buffered variant as well

tag fileflag {
    append;
    create;
    truncate;
    none;
}

type buf_writer = state obj {
  fn write(vec[u8] v);

  fn seek(int offset, seek_style whence);
  fn tell() -> uint; // TODO: eventually u64
};

state obj FILE_writer(os.libc.FILE f, bool must_close) {
    fn write(vec[u8] v) {
        auto len = _vec.len[u8](v);
        auto vbuf = _vec.buf[u8](v);
        auto nout = os.libc.fwrite(vbuf, len, 1u, f);
        if (nout < 1u) {
            log "error dumping buffer";
        }
    }

    fn seek(int offset, seek_style whence) {
        check(os.libc.fseek(f, offset, convert_whence(whence)) == 0);
    }

    fn tell() -> uint {
        ret os.libc.ftell(f) as uint;
    }

    drop {
        if (must_close) {os.libc.fclose(f);}
    }
}

state obj fd_buf_writer(int fd, bool must_close) {
    fn write(vec[u8] v) {
        auto len = _vec.len[u8](v);
        auto count = 0u;
        auto vbuf;
        while (count < len) {
            vbuf = _vec.buf_off[u8](v, count);
            auto nout = os.libc.write(fd, vbuf, len);
            if (nout < 0) {
                log "error dumping buffer";
                log sys.rustrt.last_os_error();
                fail;
            }
            count += nout as uint;
        }
    }

    fn seek(int offset, seek_style whence) {
        log "need 64-bit native calls for seek, sorry";
        fail;
    }

    fn tell() -> uint {
        log "need 64-bit native calls for tell, sorry";
        fail;
    }

    drop {
        if (must_close) {os.libc.close(fd);}
    }
}

fn file_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
    let int fflags =
        os.libc_constants.O_WRONLY() |
        os.libc_constants.O_BINARY();

    for (fileflag f in flags) {
        alt (f) {
            case (append)   { fflags |= os.libc_constants.O_APPEND(); }
            case (create)   { fflags |= os.libc_constants.O_CREAT(); }
            case (truncate) { fflags |= os.libc_constants.O_TRUNC(); }
            case (none) {}
        }
    }

    auto fd = os.libc.open(_str.buf(path),
                           fflags,
                           os.libc_constants.S_IRUSR() |
                           os.libc_constants.S_IWUSR());

    if (fd < 0) {
        log "error opening file for writing";
        log sys.rustrt.last_os_error();
        fail;
    }
    ret fd_buf_writer(fd, true);
}

type writer =
    state obj {
          impure fn write_str(str s);
          impure fn write_int(int n);
          impure fn write_uint(uint n);
          impure fn write_bytes(vec[u8] bytes);
          impure fn write_le_uint(uint n, uint size);
          impure fn write_le_int(int n, uint size);
    };

fn uint_to_le_bytes(uint n, uint size) -> vec[u8] {
    let vec[u8] bytes = vec();
    while (size > 0u) {
        bytes += vec((n & 255u) as u8);
        n >>= 8u;
        size -= 1u;
    }
    ret bytes;
}

state obj new_writer(buf_writer out) {
    impure fn write_str(str s) {
        out.write(_str.bytes(s));
    }
    impure fn write_int(int n) {
        out.write(_str.bytes(_int.to_str(n, 10u)));
    }
    impure fn write_uint(uint n) {
        out.write(_str.bytes(_uint.to_str(n, 10u)));
    }
    impure fn write_bytes(vec[u8] bytes) {
        out.write(bytes);
    }
    impure fn write_le_uint(uint n, uint size) {
        out.write(uint_to_le_bytes(n, size));
    }
    impure fn write_le_int(int n, uint size) {
        out.write(uint_to_le_bytes(n as uint, size));
    }
}

fn file_writer(str path, vec[fileflag] flags) -> writer {
    ret new_writer(file_buf_writer(path, flags));
}

// FIXME it would be great if this could be a const
fn stdout() -> writer {
    ret new_writer(fd_buf_writer(1, false));
}

type str_writer =
    state obj {
          fn get_writer() -> writer;
          fn get_str() -> str;
    };

type byte_buf = @rec(mutable vec[mutable u8] buf, mutable uint pos);

state obj byte_buf_writer(byte_buf buf) {
    fn write(vec[u8] v) {
        // TODO: optimize
        auto vlen = _vec.len[u8](v);
        auto vpos = 0u;
        while (vpos < vlen) {
            auto b = v.(vpos);
            if (buf.pos == _vec.len[mutable u8](buf.buf)) {
                buf.buf += vec(mutable b);
            } else {
                buf.buf.(buf.pos) = b;
            }
            buf.pos += 1u;
            vpos += 1u;
        }
    }

    fn seek(int offset, seek_style whence) {
        auto pos = buf.pos as int;
        auto len = _vec.len[mutable u8](buf.buf) as int;
        alt (whence) {
            case (seek_set) { pos = offset;         }
            case (seek_cur) { pos += offset;        }
            case (seek_end) { pos = len + offset;   }
        }

        if (pos < 0) {
            pos = 0;
        } else if (pos > len) {
            pos = len;
        }

        buf.pos = pos as uint;
    }

    fn tell() -> uint { ret buf.pos; }
}

// TODO awkward! it's not possible to implement a writer with an extra method
fn string_writer() -> str_writer {
    // FIXME: yikes, this is bad. Needs fixing of mutable syntax.
    let vec[mutable u8] b = vec(mutable 0u8);
    _vec.pop[mutable u8](b);

    let byte_buf buf = @rec(mutable buf = b, mutable pos = 0u);
    state obj str_writer_wrap(writer wr, byte_buf buf) {
        fn get_writer() -> writer {ret wr;}
        fn get_str() -> str {ret _str.unsafe_from_mutable_bytes(buf.buf);}
    }
    ret str_writer_wrap(new_writer(byte_buf_writer(buf)), buf);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<commit_msg>stdlib: Add a convenience method for opening paths as a FILE<commit_after>import os.libc;

native "rust" mod rustrt {
  fn rust_get_stdin() -> os.libc.FILE;
  fn rust_get_stdout() -> os.libc.FILE;
}

// Reading

// TODO This is all buffered. We might need an unbuffered variant as well

tag seek_style {seek_set; seek_end; seek_cur;}

type reader =
    state obj {
          impure fn read_byte() -> u8;
          impure fn read_bytes(uint len) -> vec[u8];
          impure fn read_char() -> int;
          impure fn unread_char(int i);
          impure fn eof() -> bool;
          impure fn read_line() -> str;
          impure fn read_c_str() -> str;
          impure fn read_le_uint(uint size) -> uint;
          impure fn read_le_int(uint size) -> int;

          impure fn seek(int offset, seek_style whence);
          impure fn tell() -> uint; // TODO: eventually u64
    };

fn convert_whence(seek_style whence) -> int {
    alt (whence) {
        case (seek_set) {ret 0;}
        case (seek_cur) {ret 1;}
        case (seek_end) {ret 2;}
    }
}

state obj FILE_reader(os.libc.FILE f, bool must_close) {
    impure fn read_byte() -> u8 {
        ret os.libc.fgetc(f) as u8;
    }
    impure fn read_bytes(uint len) -> vec[u8] {
        auto buf = _vec.alloc[u8](len);
        auto read = os.libc.fread(_vec.buf[u8](buf), 1u, len, f);
        _vec.len_set[u8](buf, read);
        ret buf;
    }
    impure fn read_char() -> int {
        ret os.libc.fgetc(f);
    }
    impure fn unread_char(int ch) {
        os.libc.ungetc(ch, f);
    }
    impure fn eof() -> bool {
      auto ch = os.libc.fgetc(f);
      if (ch == -1) {ret true;}
      os.libc.ungetc(ch, f);
      ret false;
    }
    impure fn read_line() -> str {
      auto buf = "";
      while (true) {
        auto ch = os.libc.fgetc(f);
        if (ch == -1) { ret buf; }
        if (ch == 10) { ret buf; }
        buf += _str.unsafe_from_bytes(vec(ch as u8));
      }
      ret buf;
    }
    impure fn read_c_str() -> str {
        auto buf = "";
        while (true) {
            auto ch = os.libc.fgetc(f);
            if (ch < 1) { ret buf; }
            buf += _str.unsafe_from_bytes(vec(ch as u8));
        }
        ret buf;
    }
    // TODO deal with eof?
    impure fn read_le_uint(uint size) -> uint {
        auto val = 0u;
        auto pos = 0u;
        while (size > 0u) {
            val += (os.libc.fgetc(f) as uint) << pos;
            pos += 8u;
            size -= 1u;
        }
        ret val;
    }
    impure fn read_le_int(uint size) -> int {
        auto val = 0u;
        auto pos = 0u;
        while (size > 0u) {
            val += (os.libc.fgetc(f) as uint) << pos;
            pos += 8u;
            size -= 1u;
        }
        ret val as int; // TODO does that work?
    }
    impure fn seek(int offset, seek_style whence) {
        check(os.libc.fseek(f, offset, convert_whence(whence)) == 0);
    }
    impure fn tell() -> uint {
        ret os.libc.ftell(f) as uint;
    }
    drop {
        if (must_close) {os.libc.fclose(f);}
    }
}

fn stdin() -> reader {
    ret FILE_reader(rustrt.rust_get_stdin(), false);
}

fn file_reader(str path) -> reader {
    auto f = os.libc.fopen(_str.buf(path), _str.buf("r"));
    if (f as uint == 0u) {
        log "error opening " + path;
        fail;
    }
    ret FILE_reader(f, true);
}

// Writing

// TODO This is all unbuffered. We might need a buffered variant as well

tag fileflag {
    append;
    create;
    truncate;
    none;
}

type buf_writer = state obj {
  fn write(vec[u8] v);

  fn seek(int offset, seek_style whence);
  fn tell() -> uint; // TODO: eventually u64
};

state obj FILE_writer(os.libc.FILE f, bool must_close) {
    fn write(vec[u8] v) {
        auto len = _vec.len[u8](v);
        auto vbuf = _vec.buf[u8](v);
        auto nout = os.libc.fwrite(vbuf, len, 1u, f);
        if (nout < 1u) {
            log "error dumping buffer";
        }
    }

    fn seek(int offset, seek_style whence) {
        check(os.libc.fseek(f, offset, convert_whence(whence)) == 0);
    }

    fn tell() -> uint {
        ret os.libc.ftell(f) as uint;
    }

    drop {
        if (must_close) {os.libc.fclose(f);}
    }
}

state obj fd_buf_writer(int fd, bool must_close) {
    fn write(vec[u8] v) {
        auto len = _vec.len[u8](v);
        auto count = 0u;
        auto vbuf;
        while (count < len) {
            vbuf = _vec.buf_off[u8](v, count);
            auto nout = os.libc.write(fd, vbuf, len);
            if (nout < 0) {
                log "error dumping buffer";
                log sys.rustrt.last_os_error();
                fail;
            }
            count += nout as uint;
        }
    }

    fn seek(int offset, seek_style whence) {
        log "need 64-bit native calls for seek, sorry";
        fail;
    }

    fn tell() -> uint {
        log "need 64-bit native calls for tell, sorry";
        fail;
    }

    drop {
        if (must_close) {os.libc.close(fd);}
    }
}

fn file_buf_writer(str path, vec[fileflag] flags) -> buf_writer {
    let int fflags =
        os.libc_constants.O_WRONLY() |
        os.libc_constants.O_BINARY();

    for (fileflag f in flags) {
        alt (f) {
            case (append)   { fflags |= os.libc_constants.O_APPEND(); }
            case (create)   { fflags |= os.libc_constants.O_CREAT(); }
            case (truncate) { fflags |= os.libc_constants.O_TRUNC(); }
            case (none) {}
        }
    }

    auto fd = os.libc.open(_str.buf(path),
                           fflags,
                           os.libc_constants.S_IRUSR() |
                           os.libc_constants.S_IWUSR());

    if (fd < 0) {
        log "error opening file for writing";
        log sys.rustrt.last_os_error();
        fail;
    }
    ret fd_buf_writer(fd, true);
}

type writer =
    state obj {
          impure fn write_str(str s);
          impure fn write_int(int n);
          impure fn write_uint(uint n);
          impure fn write_bytes(vec[u8] bytes);
          impure fn write_le_uint(uint n, uint size);
          impure fn write_le_int(int n, uint size);
    };

fn uint_to_le_bytes(uint n, uint size) -> vec[u8] {
    let vec[u8] bytes = vec();
    while (size > 0u) {
        bytes += vec((n & 255u) as u8);
        n >>= 8u;
        size -= 1u;
    }
    ret bytes;
}

state obj new_writer(buf_writer out) {
    impure fn write_str(str s) {
        out.write(_str.bytes(s));
    }
    impure fn write_int(int n) {
        out.write(_str.bytes(_int.to_str(n, 10u)));
    }
    impure fn write_uint(uint n) {
        out.write(_str.bytes(_uint.to_str(n, 10u)));
    }
    impure fn write_bytes(vec[u8] bytes) {
        out.write(bytes);
    }
    impure fn write_le_uint(uint n, uint size) {
        out.write(uint_to_le_bytes(n, size));
    }
    impure fn write_le_int(int n, uint size) {
        out.write(uint_to_le_bytes(n as uint, size));
    }
}

fn file_writer(str path, vec[fileflag] flags) -> writer {
    ret new_writer(file_buf_writer(path, flags));
}

// TODO: fileflags
fn buffered_file_buf_writer(str path) -> buf_writer {
    auto f = os.libc.fopen(_str.buf(path), _str.buf("w"));
    if (f as uint == 0u) {
        log "error opening " + path;
        fail;
    }
    ret FILE_writer(f, true);
}

// FIXME it would be great if this could be a const
fn stdout() -> writer {
    ret new_writer(fd_buf_writer(1, false));
}

type str_writer =
    state obj {
          fn get_writer() -> writer;
          fn get_str() -> str;
    };

type byte_buf = @rec(mutable vec[mutable u8] buf, mutable uint pos);

state obj byte_buf_writer(byte_buf buf) {
    fn write(vec[u8] v) {
        // TODO: optimize
        auto vlen = _vec.len[u8](v);
        auto vpos = 0u;
        while (vpos < vlen) {
            auto b = v.(vpos);
            if (buf.pos == _vec.len[mutable u8](buf.buf)) {
                buf.buf += vec(mutable b);
            } else {
                buf.buf.(buf.pos) = b;
            }
            buf.pos += 1u;
            vpos += 1u;
        }
    }

    fn seek(int offset, seek_style whence) {
        auto pos = buf.pos as int;
        auto len = _vec.len[mutable u8](buf.buf) as int;
        alt (whence) {
            case (seek_set) { pos = offset;         }
            case (seek_cur) { pos += offset;        }
            case (seek_end) { pos = len + offset;   }
        }

        if (pos < 0) {
            pos = 0;
        } else if (pos > len) {
            pos = len;
        }

        buf.pos = pos as uint;
    }

    fn tell() -> uint { ret buf.pos; }
}

// TODO awkward! it's not possible to implement a writer with an extra method
fn string_writer() -> str_writer {
    // FIXME: yikes, this is bad. Needs fixing of mutable syntax.
    let vec[mutable u8] b = vec(mutable 0u8);
    _vec.pop[mutable u8](b);

    let byte_buf buf = @rec(mutable buf = b, mutable pos = 0u);
    state obj str_writer_wrap(writer wr, byte_buf buf) {
        fn get_writer() -> writer {ret wr;}
        fn get_str() -> str {ret _str.unsafe_from_mutable_bytes(buf.buf);}
    }
    ret str_writer_wrap(new_writer(byte_buf_writer(buf)), buf);
}

//
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C .. 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
//
<|endoftext|>


<commit_before>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
    /// [invite-notify](http://ircv3.net/specs/extensions/invite-notify-3.2.html)
    InviteNotify,
    /// [server-time](http://ircv3.net/specs/extensions/server-time-3.2.html)
    ServerTime,
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
            Capability::InviteNotify => "invite-notify",
            Capability::ServerTime => "server-time",
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
        assert_eq!(InviteNotify.as_ref(), "invite-notify");
        assert_eq!(ServerTime.as_ref(), "server-time");
    }
}
<commit_msg>Added support for userhost-in-names capability.<commit_after>//! Enumeration of all supported IRCv3 capability extensions.

/// List of all supported IRCv3 capability extensions from the
/// [IRCv3 specifications](http://ircv3.net/irc/).
#[derive(Debug, PartialEq)]
pub enum Capability {
    /// [multi-prefix](http://ircv3.net/specs/extensions/multi-prefix-3.1.html)
    MultiPrefix,
    /// [account-notify](http://ircv3.net/specs/extensions/account-notify-3.1.html)
    AccountNotify,
    /// [away-notify](http://ircv3.net/specs/extensions/away-notify-3.1.html)
    AwayNotify,
    /// [extended-join](http://ircv3.net/specs/extensions/extended-join-3.1.html)
    ExtendedJoin,
    /// [monitor](http://ircv3.net/specs/core/monitor-3.2.html)
    Monitor,
    /// [account-tag](http://ircv3.net/specs/extensions/account-tag-3.2.html)
    AccountTag,
    /// [cap-notify](http://ircv3.net/specs/extensions/cap-notify-3.2.html)
    CapNotify,
    /// [chghost](http://ircv3.net/specs/extensions/chghost-3.2.html)
    ChgHost,
    /// [echo-message](http://ircv3.net/specs/extensions/echo-message-3.2.html)
    EchoMessage,
    /// [invite-notify](http://ircv3.net/specs/extensions/invite-notify-3.2.html)
    InviteNotify,
    /// [server-time](http://ircv3.net/specs/extensions/server-time-3.2.html)
    ServerTime,
    /// [userhost-in-names](http://ircv3.net/specs/extensions/userhost-in-names-3.2.html)
    UserhostInNames,
}

/// List of IRCv3 capability negotiation versions.
pub enum NegotiationVersion {
    /// [IRCv3.1](http://ircv3.net/specs/core/capability-negotiation-3.1.html)
    V301,
    /// [IRCv3.2](http://ircv3.net/specs/core/capability-negotiation-3.2.html)
    V302,
}

impl AsRef<str> for Capability {
    fn as_ref(&self) -> &str {
        match *self {
            Capability::MultiPrefix => "multi-prefix",
            Capability::AccountNotify => "account-notify",
            Capability::AwayNotify => "away-notify",
            Capability::ExtendedJoin => "extended-join",
            Capability::Monitor => "monitor",
            Capability::AccountTag => "account-tag",
            Capability::CapNotify => "cap-notify",
            Capability::ChgHost => "chghost",
            Capability::EchoMessage => "echo-message",
            Capability::InviteNotify => "invite-notify",
            Capability::ServerTime => "server-time",
            Capability::UserhostInNames => "userhost-in-names",
        }
    }
}

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

    #[test]
    fn to_str() {
        assert_eq!(MultiPrefix.as_ref(), "multi-prefix");
        assert_eq!(AccountNotify.as_ref(), "account-notify");
        assert_eq!(AwayNotify.as_ref(), "away-notify");
        assert_eq!(ExtendedJoin.as_ref(), "extended-join");
        assert_eq!(Monitor.as_ref(), "monitor");
        assert_eq!(AccountTag.as_ref(), "account-tag");
        assert_eq!(CapNotify.as_ref(), "cap-notify");
        assert_eq!(ChgHost.as_ref(), "chghost");
        assert_eq!(EchoMessage.as_ref(), "echo-message");
        assert_eq!(InviteNotify.as_ref(), "invite-notify");
        assert_eq!(ServerTime.as_ref(), "server-time");
        assert_eq!(UserhostInNames.as_ref(), "userhost-in-names");
    }
}
<|endoftext|>


<commit_before>/// Return early with an error.
///
/// This macro is equivalent to `return Err(`[`anyhow!($args...)`][anyhow!]`)`.
///
/// The surrounding function's or closure's return value is required to be
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
///
/// # Example
///
/// ```
/// # use anyhow::{bail, Result};
/// #
/// # fn has_permission(user: usize, resource: usize) -> bool {
/// #     true
/// # }
/// #
/// # fn main() -> Result<()> {
/// #     let user = 0;
/// #     let resource = 0;
/// #
/// if !has_permission(user, resource) {
///     bail!("permission denied for accessing {}", resource);
/// }
/// #     Ok(())
/// # }
/// ```
///
/// ```
/// # use anyhow::{bail, Result};
/// # use thiserror::Error;
/// #
/// # const MAX_DEPTH: usize = 1;
/// #
/// #[derive(Error, Debug)]
/// enum ScienceError {
///     #[error("recursion limit exceeded")]
///     RecursionLimitExceeded,
///     # #[error("...")]
///     # More = (stringify! {
///     ...
///     # }, 1).1,
/// }
///
/// # fn main() -> Result<()> {
/// #     let depth = 0;
/// #
/// if depth > MAX_DEPTH {
///     bail!(ScienceError::RecursionLimitExceeded);
/// }
/// #     Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! bail {
    ($msg:literal $(,)?) => {
        return $crate::private::Err($crate::anyhow!($msg))
    };
    ($err:expr $(,)?) => {
        return $crate::private::Err($crate::anyhow!($err))
    };
    ($fmt:expr, $($arg:tt)*) => {
        return $crate::private::Err($crate::anyhow!($fmt, $($arg)*))
    };
}

/// Return early with an error if a condition is not satisfied.
///
/// This macro is equivalent to `if !$cond { return
/// Err(`[`anyhow!($args...)`][anyhow!]`); }`.
///
/// The surrounding function's or closure's return value is required to be
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
///
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
/// rather than panicking.
///
/// # Example
///
/// ```
/// # use anyhow::{ensure, Result};
/// #
/// # fn main() -> Result<()> {
/// #     let user = 0;
/// #
/// ensure!(user == 0, "only user 0 is allowed");
/// #     Ok(())
/// # }
/// ```
///
/// ```
/// # use anyhow::{ensure, Result};
/// # use thiserror::Error;
/// #
/// # const MAX_DEPTH: usize = 1;
/// #
/// #[derive(Error, Debug)]
/// enum ScienceError {
///     #[error("recursion limit exceeded")]
///     RecursionLimitExceeded,
///     # #[error("...")]
///     # More = (stringify! {
///     ...
///     # }, 1).1,
/// }
///
/// # fn main() -> Result<()> {
/// #     let depth = 0;
/// #
/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
/// #     Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! ensure {
    ($cond:expr $(,)?) => {
        $crate::ensure!(
            $cond,
            $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`"),
        )
    };
    ($cond:expr, $msg:literal $(,)?) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($msg));
        }
    };
    ($cond:expr, $err:expr $(,)?) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($err));
        }
    };
    ($cond:expr, $fmt:expr, $($arg:tt)*) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($fmt, $($arg)*));
        }
    };
}

/// Construct an ad-hoc error from a string or existing non-`anyhow` error
/// value.
///
/// This evaluates to an [`Error`][crate::Error]. It can take either just a
/// string, or a format string with arguments. It also can take any custom type
/// which implements `Debug` and `Display`.
///
/// If called with a single argument whose type implements `std::error::Error`
/// (in addition to `Debug` and `Display`, which are always required), then that
/// Error impl's `source` is preserved as the `source` of the resulting
/// `anyhow::Error`.
///
/// # Example
///
/// ```
/// # type V = ();
/// #
/// use anyhow::{anyhow, Result};
///
/// fn lookup(key: &str) -> Result<V> {
///     if key.len() != 16 {
///         return Err(anyhow!("key length must be 16 characters, got {:?}", key));
///     }
///
///     // ...
///     # Ok(())
/// }
/// ```
#[macro_export]
macro_rules! anyhow {
    ($msg:literal $(,)?) => {
        // Handle $:literal as a special case to make cargo-expanded code more
        // concise in the common case.
        $crate::private::new_adhoc($msg)
    };
    ($err:expr $(,)?) => ({
        use $crate::private::kind::*;
        match $err {
            error => (&error).anyhow_kind().new(error),
        }
    });
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}
<commit_msg>Bypass anyhow_kind-based dispatch for ensure! with default msg<commit_after>/// Return early with an error.
///
/// This macro is equivalent to `return Err(`[`anyhow!($args...)`][anyhow!]`)`.
///
/// The surrounding function's or closure's return value is required to be
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
///
/// # Example
///
/// ```
/// # use anyhow::{bail, Result};
/// #
/// # fn has_permission(user: usize, resource: usize) -> bool {
/// #     true
/// # }
/// #
/// # fn main() -> Result<()> {
/// #     let user = 0;
/// #     let resource = 0;
/// #
/// if !has_permission(user, resource) {
///     bail!("permission denied for accessing {}", resource);
/// }
/// #     Ok(())
/// # }
/// ```
///
/// ```
/// # use anyhow::{bail, Result};
/// # use thiserror::Error;
/// #
/// # const MAX_DEPTH: usize = 1;
/// #
/// #[derive(Error, Debug)]
/// enum ScienceError {
///     #[error("recursion limit exceeded")]
///     RecursionLimitExceeded,
///     # #[error("...")]
///     # More = (stringify! {
///     ...
///     # }, 1).1,
/// }
///
/// # fn main() -> Result<()> {
/// #     let depth = 0;
/// #
/// if depth > MAX_DEPTH {
///     bail!(ScienceError::RecursionLimitExceeded);
/// }
/// #     Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! bail {
    ($msg:literal $(,)?) => {
        return $crate::private::Err($crate::anyhow!($msg))
    };
    ($err:expr $(,)?) => {
        return $crate::private::Err($crate::anyhow!($err))
    };
    ($fmt:expr, $($arg:tt)*) => {
        return $crate::private::Err($crate::anyhow!($fmt, $($arg)*))
    };
}

/// Return early with an error if a condition is not satisfied.
///
/// This macro is equivalent to `if !$cond { return
/// Err(`[`anyhow!($args...)`][anyhow!]`); }`.
///
/// The surrounding function's or closure's return value is required to be
/// `Result<_,`[`anyhow::Error`][crate::Error]`>`.
///
/// Analogously to `assert!`, `ensure!` takes a condition and exits the function
/// if the condition fails. Unlike `assert!`, `ensure!` returns an `Error`
/// rather than panicking.
///
/// # Example
///
/// ```
/// # use anyhow::{ensure, Result};
/// #
/// # fn main() -> Result<()> {
/// #     let user = 0;
/// #
/// ensure!(user == 0, "only user 0 is allowed");
/// #     Ok(())
/// # }
/// ```
///
/// ```
/// # use anyhow::{ensure, Result};
/// # use thiserror::Error;
/// #
/// # const MAX_DEPTH: usize = 1;
/// #
/// #[derive(Error, Debug)]
/// enum ScienceError {
///     #[error("recursion limit exceeded")]
///     RecursionLimitExceeded,
///     # #[error("...")]
///     # More = (stringify! {
///     ...
///     # }, 1).1,
/// }
///
/// # fn main() -> Result<()> {
/// #     let depth = 0;
/// #
/// ensure!(depth <= MAX_DEPTH, ScienceError::RecursionLimitExceeded);
/// #     Ok(())
/// # }
/// ```
#[macro_export]
macro_rules! ensure {
    ($cond:expr $(,)?) => {
        if !$cond {
            return $crate::private::Err($crate::private::new_adhoc(
                $crate::private::concat!("Condition failed: `", $crate::private::stringify!($cond), "`")
            ));
        }
    };
    ($cond:expr, $msg:literal $(,)?) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($msg));
        }
    };
    ($cond:expr, $err:expr $(,)?) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($err));
        }
    };
    ($cond:expr, $fmt:expr, $($arg:tt)*) => {
        if !$cond {
            return $crate::private::Err($crate::anyhow!($fmt, $($arg)*));
        }
    };
}

/// Construct an ad-hoc error from a string or existing non-`anyhow` error
/// value.
///
/// This evaluates to an [`Error`][crate::Error]. It can take either just a
/// string, or a format string with arguments. It also can take any custom type
/// which implements `Debug` and `Display`.
///
/// If called with a single argument whose type implements `std::error::Error`
/// (in addition to `Debug` and `Display`, which are always required), then that
/// Error impl's `source` is preserved as the `source` of the resulting
/// `anyhow::Error`.
///
/// # Example
///
/// ```
/// # type V = ();
/// #
/// use anyhow::{anyhow, Result};
///
/// fn lookup(key: &str) -> Result<V> {
///     if key.len() != 16 {
///         return Err(anyhow!("key length must be 16 characters, got {:?}", key));
///     }
///
///     // ...
///     # Ok(())
/// }
/// ```
#[macro_export]
macro_rules! anyhow {
    ($msg:literal $(,)?) => {
        // Handle $:literal as a special case to make cargo-expanded code more
        // concise in the common case.
        $crate::private::new_adhoc($msg)
    };
    ($err:expr $(,)?) => ({
        use $crate::private::kind::*;
        match $err {
            error => (&error).anyhow_kind().new(error),
        }
    });
    ($fmt:expr, $($arg:tt)*) => {
        $crate::private::new_adhoc(format!($fmt, $($arg)*))
    };
}
<|endoftext|>


<commit_before>extern crate primes;
extern crate num;
use primes::PrimeSet;
use num::{BigUint, Zero, One};
use num::bigint::ToBigUint;

static MANY_DIGIT: &'static str = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";

fn p1(max: u64) -> u64 {
    let sum = (1..max + 1).fold(0u64, |acc, i| {
        if i%3 == 0 || i%5 ==0 {
            acc + i
        } else {
            acc
        }
    });
    sum
}

fn p6(max: u64) -> u64 {
    let max = max + 1;
    let sum_of_squares = (1..max).fold(0u64, |acc, i| acc + (i * i));
    let sum = (1..max).fold(0u64, |acc, i| acc + i);
    let square_of_sums = sum * sum;
    square_of_sums - sum_of_squares
}

fn p7(max: usize) -> u64 {
    let max = max - 1;
    let mut pset = PrimeSet::new();
    let prime = pset.get(max);
    prime
}

fn p8(width: usize) -> BigUint {
    let nums: Vec<(char)> = MANY_DIGIT.chars().collect();

    let mut start = 0;
    let mut length = width;
    let max = nums.len();
    let mut high_total: BigUint = Zero::zero();
    while length < max {
        let curr_total = (start..length).fold(One::one(), |acc, i| acc * nums[i].to_digit(10).unwrap().to_biguint().unwrap());
        if curr_total > high_total {
            high_total = curr_total;
        }
        start += 1;
        length += 1;
    }
    high_total
}

fn main() {
    println!("{}", p1(1000));
    println!("{}", p6(100));
    println!("{}", p7(10_001));
    println!("{}", p8(13));
}
<commit_msg>using test structure<commit_after>#![allow(dead_code)]
#![allow(unused_imports)]
extern crate primes;
extern crate num;
use primes::PrimeSet;
//use num::{BigUint, Zero, One};
//use num::bigint::ToBigUint;

/// ### [Multiples of 3 and 5](https://projecteuler.net/problem=1)
/// If we list all the natural numbers below 10 that are multiples of 3 or 5, we get 3, 5, 6 and 9. The sum of these multiples is 23.
/// Find the sum of all the multiples of 3 or 5 below 1000.
///
/// # Examples
/// ```
/// use euler::p1;
/// assert_eq!(233_168, p1(1_000));
/// ```
pub fn p1(max: u64) -> u64 {
    (1..max).fold(0u64, |acc, i| {
        if i%3 == 0 || i%5 == 0 {
            acc + i
        } else {
            acc
        }
    })
}

/// ### [Even Fibonacci numbers](https://projecteuler.net/problem=2)
/// Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be: `1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...`
/// By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
///
/// # Examples
/// ```
/// use euler::p2;
/// assert_eq!(4_613_732, p2(4_000_000));
/// ```
pub fn p2(max: u64) -> u64 {
    unimplemented!();
}

/// ### [Largest prime factor](https://projecteuler.net/problem=3)
/// The prime factors of 13195 are 5, 7, 13 and 29.
/// What is the largest prime factor of the number 600851475143?
///
/// # Examples
/// ```
/// use euler::p3;
/// assert_eq!(6857, p3(600_851_475_143));
/// ```
pub fn p3(max: u64) -> u64 {
    unimplemented!();
}

/// ### [Largest palindrome product](https://projecteuler.net/problem=4)
/// A palindromic number reads the same both ways. The largest palindrome made from the product of two 2-digit numbers is 9009 = 91 × 99.
/// Find the largest palindrome made from the product of two 3-digit numbers.
///
/// # Examples
/// ```
/// use euler::p4;
/// assert_eq!(906_609, p4(999));
/// ```
pub fn p4(max: u64) -> u64 {
    unimplemented!();
}

/// ### [Smallest multiple](https://projecteuler.net/problem=5)
/// 2520 is the smallest number that can be divided by each of the numbers from 1 to 10 without any remainder.
/// What is the smallest positive number that is evenly divisible by all of the numbers from 1 to 20?
///
/// # Examples
/// ```
/// use euler::p5;
/// assert_eq!(232_792_560, p5(20));
/// ```
pub fn p5(max: u64) -> u64 {
    unimplemented!();
}

/// ### [Sum square difference](https://projecteuler.net/problem=6)
/// The sum of the squares of the first ten natural numbers is, `12 + 22 + ... + 102 = 385`.
/// The square of the sum of the first ten natural numbers is, `(1 + 2 + ... + 10)2 = 552 = 3025`.
/// Hence the difference between the sum of the squares of the first ten natural numbers and the square of the sum is 3025 − 385 = 2640.
/// Find the difference between the sum of the squares of the first one hundred natural numbers and the square of the sum.
///
/// # Examples
/// ```
/// use euler::p6;
/// assert_eq!(25_164_150, p6(100));
/// ```
pub fn p6(max: u64) -> u64 {
    let max = max + 1;
    let sum_of_squares = (1..max).fold(0u64, |acc, i| acc + (i * i));
    let sum = (1..max).fold(0u64, |acc, i| acc + i);
    let square_of_sums = sum * sum;
    square_of_sums - sum_of_squares
}

/// ### [10001st prime](https://projecteuler.net/problem=7)
/// By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.
/// What is the 10,001st prime number?
///
/// # Examples
/// ```
/// use euler::p7;
/// assert_eq!(104743, p7(10_001));
/// ```
pub fn p7(max: usize) -> u64 {
    let max = max - 1;
    let mut pset = PrimeSet::new();
    let prime = pset.get(max);
    prime
}

/// ### [Largest product in a series](https://projecteuler.net/problem=8)
/// The four adjacent digits in the 1000-digit number that have the greatest product are 9 × 9 × 8 × 9 = 5832.
/// Find the thirteen adjacent digits in the 1000-digit number that have the greatest product. What is the value of this product?
///
/// ```text
/// 73167176531330624919225119674426574742355349194934
/// 96983520312774506326239578318016984801869478851843
/// 85861560789112949495459501737958331952853208805511
/// 12540698747158523863050715693290963295227443043557
/// 66896648950445244523161731856403098711121722383113
/// 62229893423380308135336276614282806444486645238749
/// 30358907296290491560440772390713810515859307960866
/// 70172427121883998797908792274921901699720888093776
/// 65727333001053367881220235421809751254540594752243
/// 52584907711670556013604839586446706324415722155397
/// 53697817977846174064955149290862569321978468622482
/// 83972241375657056057490261407972968652414535100474
/// 82166370484403199890008895243450658541227588666881
/// 16427171479924442928230863465674813919123162824586
/// 17866458359124566529476545682848912883142607690042
/// 24219022671055626321111109370544217506941658960408
/// 07198403850962455444362981230987879927244284909188
/// 84580156166097919133875499200524063689912560717606
/// 05886116467109405077541002256983155200055935729725
/// 71636269561882670428252483600823257530420752963450
/// ```
///
/// # Examples
/// ```
/// use euler::p8;
/// assert_eq!(23_514_624_000, p8(13));
/// ```
pub fn p8(width: usize) -> u64 {
    static MANY_DIGIT: &'static str = "7316717653133062491922511967442657474235534919493496983520312774506326239578318016984801869478851843858615607891129494954595017379583319528532088055111254069874715852386305071569329096329522744304355766896648950445244523161731856403098711121722383113622298934233803081353362766142828064444866452387493035890729629049156044077239071381051585930796086670172427121883998797908792274921901699720888093776657273330010533678812202354218097512545405947522435258490771167055601360483958644670632441572215539753697817977846174064955149290862569321978468622482839722413756570560574902614079729686524145351004748216637048440319989000889524345065854122758866688116427171479924442928230863465674813919123162824586178664583591245665294765456828489128831426076900422421902267105562632111110937054421750694165896040807198403850962455444362981230987879927244284909188845801561660979191338754992005240636899125607176060588611646710940507754100225698315520005593572972571636269561882670428252483600823257530420752963450";

    let nums: Vec<(char)> = MANY_DIGIT.chars().collect();

    let mut start = 0;
    let mut length = width;
    let max = nums.len();
    let mut high_total: u64 = 0;
    while length < max {
        let curr_total = (start..length).fold(1, |acc, i| acc * nums[i].to_digit(10).unwrap() as u64);
        if curr_total > high_total {
            high_total = curr_total;
        }
        start += 1;
        length += 1;
    }
    high_total
}<|endoftext|>


<commit_before>extern crate glium;

use std::mem::zeroed;
use std::ops::*;
use glium::uniforms::*;

#[derive(PartialEq, Clone, Debug)]
pub struct Matrix { m: [[f32; 4]; 4] }

impl Matrix {
    pub fn zero() -> Self { unsafe { zeroed() } }

    pub fn new(
        m00: f32, m01: f32, m02: f32, m03: f32,
        m10: f32, m11: f32, m12: f32, m13: f32,
        m20: f32, m21: f32, m22: f32, m23: f32,
        m30: f32, m31: f32, m32: f32, m33: f32,
    ) -> Self {
        Matrix {
            m: [
                [ m00, m01, m02, m03 ],
                [ m10, m11, m12, m13 ],
                [ m20, m21, m22, m23 ],
                [ m30, m31, m32, m33 ],
            ]
        }
    }

    pub fn identity() -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_x(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [1.0,  0.0, 0.0, 0.0],
                [0.0,  cos, sin, 0.0],
                [0.0, -sin, cos, 0.0],
                [0.0,  0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_y(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [cos, 0.0, -sin, 0.0],
                [0.0, 1.0,  0.0, 0.0],
                [sin, 0.0,  cos, 0.0],
                [0.0, 0.0,  0.0, 1.0],
            ]
        }
    }

    pub fn rotation_z(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [ cos, sin, 0.0, 0.0],
                [-sin, cos, 0.0, 0.0],
                [ 0.0, 0.0, 1.0, 0.0],
                [ 0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn orthographic(view_width: f32, view_height: f32, near_z: f32, far_z: f32) -> Self {
        // assert(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
        let f_range = 1.0/(near_z - far_z);
        Matrix {
            m: [
                [2.0/view_width, 0.0, 0.0, 0.0],
                [0.0, 2.0/view_height, 0.0, 0.0],
                [0.0, 0.0, f_range, 0.0],
                [0.0, 0.0, f_range*near_z, 1.0],
            ]
        }

    }

    pub fn orthographic_off_center(view_left: f32, view_right: f32, view_bottom: f32, view_top: f32, near_z: f32, far_z: f32) -> Self {
        // reciprocal width and height
        let r_width = 1.0/(view_right - view_left);
        let r_height = 1.0/(view_top - view_bottom);
        let range = 1.0/(near_z-far_z);

        Matrix {
            m: [
                [r_width + r_width, 0.0, 0.0, 0.0],
                [0.0, r_height + r_height, 0.0, 0.0],
                [0.0, 0.0, range, 0.0],
                [-(view_left + view_right)*r_width, -(view_top + view_bottom)*r_height, range*near_z, 1.0],
            ]
        }
    }

    pub fn perspective(width: f32, height: f32, near_z: f32, far_z: f32) -> Self {
        let two_near_z = near_z + near_z;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [two_near_z/width, 0.0, 0.0, 0.0],
                [0.0, two_near_z/height, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    /// aspect: Width / Height
    pub fn perspective_fov(fov: f32, aspect: f32, near_z: f32, far_z: f32) -> Self {
        let (sin, cos) = (0.5 * fov).sin_cos();
        let f = cos/sin;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [f/aspect, 0.0, 0.0, 0.0],
                [0.0, f, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    pub fn translation(ox: f32, oy: f32, oz: f32) -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [ox,  oy,  oz,  1.0],
            ]
        }
    }

    pub fn transpose(self) -> Self {
        Matrix {
            m: [
                [self.m[0][0], self.m[1][0], self.m[2][0], self.m[3][0]],
                [self.m[0][1], self.m[1][1], self.m[2][1], self.m[3][1]],
                [self.m[0][2], self.m[1][2], self.m[2][2], self.m[3][2]],
                [self.m[0][3], self.m[1][3], self.m[2][3], self.m[3][3]],
            ]
        }
    }
}

impl Mul for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { &self * &rhs }
}

impl<'a> Mul<Matrix> for &'a Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { self * &rhs }
}

impl<'a> Mul<&'a Matrix> for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: &'a Matrix) -> Matrix { &self * rhs }
}

impl<'a, 'b> Mul<&'a Matrix> for &'b Matrix {
    type Output = Matrix;

    fn mul(self, rhs: &'a Matrix) -> Matrix {
        macro_rules! row {
            ($col:expr) => ({
                let x = self.m[$col][0];
                let y = self.m[$col][1];
                let z = self.m[$col][2];
                let w = self.m[$col][3];
                [
                    (rhs.m[0][0]*x)+(rhs.m[1][0]*y)+(rhs.m[2][0]*z)+(rhs.m[3][0]*w),
                    (rhs.m[0][1]*x)+(rhs.m[1][1]*y)+(rhs.m[2][1]*z)+(rhs.m[3][1]*w),
                    (rhs.m[0][2]*x)+(rhs.m[1][2]*y)+(rhs.m[2][2]*z)+(rhs.m[3][2]*w),
                    (rhs.m[0][3]*x)+(rhs.m[1][3]*y)+(rhs.m[2][3]*z)+(rhs.m[3][3]*w),
                ]
            })
        }

        Matrix { m: [ row!(0), row!(1), row!(2), row!(3) ] }
    }
}

impl AsUniformValue for Matrix {
    fn as_uniform_value(&self) -> UniformValue<'static> {
        UniformValue::Mat4(self.m)
    }
}

impl Index<usize> for Matrix {
    type Output = [f32;4];
    fn index<'a>(&'a self, index: usize) -> &'a Self::Output {
        &self.m[index]
    }
}
<commit_msg>Name row of matrix.<commit_after>extern crate glium;

use std::mem::zeroed;
use std::ops::*;
use glium::uniforms::*;

pub type Row = [f32; 4];

#[derive(PartialEq, Clone, Debug)]
pub struct Matrix { m: [Row; 4] }

impl Matrix {
    pub fn zero() -> Self { unsafe { zeroed() } }

    pub fn new(
        m00: f32, m01: f32, m02: f32, m03: f32,
        m10: f32, m11: f32, m12: f32, m13: f32,
        m20: f32, m21: f32, m22: f32, m23: f32,
        m30: f32, m31: f32, m32: f32, m33: f32,
    ) -> Self {
        Matrix {
            m: [
                [ m00, m01, m02, m03 ],
                [ m10, m11, m12, m13 ],
                [ m20, m21, m22, m23 ],
                [ m30, m31, m32, m33 ],
            ]
        }
    }

    pub fn identity() -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_x(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [1.0,  0.0, 0.0, 0.0],
                [0.0,  cos, sin, 0.0],
                [0.0, -sin, cos, 0.0],
                [0.0,  0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn rotation_y(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [cos, 0.0, -sin, 0.0],
                [0.0, 1.0,  0.0, 0.0],
                [sin, 0.0,  cos, 0.0],
                [0.0, 0.0,  0.0, 1.0],
            ]
        }
    }

    pub fn rotation_z(rad: f32) -> Self {
        let (sin, cos) = rad.sin_cos();

        Matrix {
            m: [
                [ cos, sin, 0.0, 0.0],
                [-sin, cos, 0.0, 0.0],
                [ 0.0, 0.0, 1.0, 0.0],
                [ 0.0, 0.0, 0.0, 1.0],
            ]
        }
    }

    pub fn orthographic(view_width: f32, view_height: f32, near_z: f32, far_z: f32) -> Self {
        // assert(!XMScalarNearEqual(ViewWidth, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(ViewHeight, 0.0f, 0.00001f));
        // assert(!XMScalarNearEqual(FarZ, NearZ, 0.00001f));
        let f_range = 1.0/(near_z - far_z);
        Matrix {
            m: [
                [2.0/view_width, 0.0, 0.0, 0.0],
                [0.0, 2.0/view_height, 0.0, 0.0],
                [0.0, 0.0, f_range, 0.0],
                [0.0, 0.0, f_range*near_z, 1.0],
            ]
        }

    }

    pub fn orthographic_off_center(view_left: f32, view_right: f32, view_bottom: f32, view_top: f32, near_z: f32, far_z: f32) -> Self {
        // reciprocal width and height
        let r_width = 1.0/(view_right - view_left);
        let r_height = 1.0/(view_top - view_bottom);
        let range = 1.0/(near_z-far_z);

        Matrix {
            m: [
                [r_width + r_width, 0.0, 0.0, 0.0],
                [0.0, r_height + r_height, 0.0, 0.0],
                [0.0, 0.0, range, 0.0],
                [-(view_left + view_right)*r_width, -(view_top + view_bottom)*r_height, range*near_z, 1.0],
            ]
        }
    }

    pub fn perspective(width: f32, height: f32, near_z: f32, far_z: f32) -> Self {
        let two_near_z = near_z + near_z;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [two_near_z/width, 0.0, 0.0, 0.0],
                [0.0, two_near_z/height, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    /// aspect: Width / Height
    pub fn perspective_fov(fov: f32, aspect: f32, near_z: f32, far_z: f32) -> Self {
        let (sin, cos) = (0.5 * fov).sin_cos();
        let f = cos/sin;
        let range = far_z/(near_z - far_z);

        Matrix {
            m: [
                [f/aspect, 0.0, 0.0, 0.0],
                [0.0, f, 0.0, 0.0],
                [0.0, 0.0, range, -1.0],
                [0.0, 0.0, range*near_z, 0.0],
            ]
        }
    }

    pub fn translation(ox: f32, oy: f32, oz: f32) -> Self {
        Matrix {
            m: [
                [1.0, 0.0, 0.0, 0.0],
                [0.0, 1.0, 0.0, 0.0],
                [0.0, 0.0, 1.0, 0.0],
                [ox,  oy,  oz,  1.0],
            ]
        }
    }

    pub fn transpose(self) -> Self {
        Matrix {
            m: [
                [self.m[0][0], self.m[1][0], self.m[2][0], self.m[3][0]],
                [self.m[0][1], self.m[1][1], self.m[2][1], self.m[3][1]],
                [self.m[0][2], self.m[1][2], self.m[2][2], self.m[3][2]],
                [self.m[0][3], self.m[1][3], self.m[2][3], self.m[3][3]],
            ]
        }
    }
}

impl Mul for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { &self * &rhs }
}

impl<'a> Mul<Matrix> for &'a Matrix {
    type Output = Matrix;
    fn mul(self, rhs: Matrix) -> Matrix { self * &rhs }
}

impl<'a> Mul<&'a Matrix> for Matrix {
    type Output = Matrix;
    fn mul(self, rhs: &'a Matrix) -> Matrix { &self * rhs }
}

impl<'a, 'b> Mul<&'a Matrix> for &'b Matrix {
    type Output = Matrix;

    fn mul(self, rhs: &'a Matrix) -> Matrix {
        macro_rules! row {
            ($col:expr) => ({
                let x = self.m[$col][0];
                let y = self.m[$col][1];
                let z = self.m[$col][2];
                let w = self.m[$col][3];
                [
                    (rhs.m[0][0]*x)+(rhs.m[1][0]*y)+(rhs.m[2][0]*z)+(rhs.m[3][0]*w),
                    (rhs.m[0][1]*x)+(rhs.m[1][1]*y)+(rhs.m[2][1]*z)+(rhs.m[3][1]*w),
                    (rhs.m[0][2]*x)+(rhs.m[1][2]*y)+(rhs.m[2][2]*z)+(rhs.m[3][2]*w),
                    (rhs.m[0][3]*x)+(rhs.m[1][3]*y)+(rhs.m[2][3]*z)+(rhs.m[3][3]*w),
                ]
            })
        }

        Matrix { m: [ row!(0), row!(1), row!(2), row!(3) ] }
    }
}

impl AsUniformValue for Matrix {
    fn as_uniform_value(&self) -> UniformValue<'static> {
        UniformValue::Mat4(self.m)
    }
}

impl Index<usize> for Matrix {
    type Output = [f32;4];
    fn index<'a>(&'a self, index: usize) -> &'a Self::Output {
        &self.m[index]
    }
}
<|endoftext|>


<commit_before>pub use src::typedefs::{mat2x2};

use src::vector::{TVec2,TVec2MulRHS};
use src::scalar::{S,SMulRHS,SDivRHS};
use std::fmt;

trait Matrix<RowVec,ColVec> {
    fn col(&self, i: uint) -> ColVec;
    fn row(&self, j: uint) -> RowVec;
}

trait Invertible {
    // (should this be Result<Self> ?)
    // (also, should this take self by value?)
    fn inverse(&self) -> Self;
}

pub fn inverse<M:Invertible>(m: &M) -> M { m.inverse() }

pub struct TMat2<T> {
    elems: [[T, ..2], ..2]
}
#[deriving(Eq,Show)]
pub struct TMat3<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4<T>; // FIXME

#[deriving(Eq,Show)]
pub struct TMat2x3<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat2x4<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat3x2<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat3x4<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4x2<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4x3<T>; // FIXME

impl<T:Clone> Matrix<TVec2<T>,TVec2<T>> for TMat2<T> {
    fn col(&self, i: uint) -> TVec2<T> {
        assert!(i <= 1);
        TVec2 { x: self.elems[0][i].clone(), y: self.elems[1][i].clone() }
    }
    fn row(&self, j: uint) -> TVec2<T> {
        assert!(j <= 1);
        TVec2 { x: self.elems[j][0].clone(), y: self.elems[j][1].clone() }
    }
}

impl<T:Num> Invertible for TMat2<T> {
    fn inverse(&self) -> TMat2<T> {
        #![allow(uppercase_variables)]
        use std::num::One;
        let m = &self.elems;
        let one : T = One::one();
        let OneOverDeterminant = one / (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
        TMat2 { elems: [[m[1][1] * OneOverDeterminant, m[0][1] * OneOverDeterminant],
                        [m[1][0] * OneOverDeterminant, m[0][0] * OneOverDeterminant]] }
    }
}

impl<T:fmt::Show> fmt::Show for TMat2<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "["));
        try!(self.elems[0].as_slice().fmt(f));
        try!(write!(f, "\n "));
        write!(f, "]")
    }
}

impl<T:Eq> Eq for TMat2<T> {
    fn eq(&self, rhs: &TMat2<T>) -> bool {
        self.elems[0] == rhs.elems[0] && self.elems[1] == rhs.elems[1]
    }
}

impl<T> TMat2<T> {
    fn map<U>(&self, f: |&T| -> U) -> TMat2<U> {
        TMat2 { elems: [[f(&self.elems[0][0]), f(&self.elems[0][1])],
                        [f(&self.elems[1][0]), f(&self.elems[1][1])]] }
    }
}

pub trait Mat2x2Args { fn make(self) -> mat2x2; }

pub fn mat2x2<Args:Mat2x2Args>(args: Args) -> mat2x2 { args.make() }
pub fn mat2<Args:Mat2x2Args>(args: Args) -> mat2x2 { args.make() }

macro_rules! impl_Mat2x2Args_for {
    ($a:ident copy) => {
        impl Mat2x2Args for $a {
            fn make(self) -> mat2x2 {
                let x = self;
                TMat2 { elems: [[x as f32,x as f32],
                                [x as f32,x as f32]] }
            }
        }
    }
    ;
    ($a:ident,$b:ident,$c:ident,$d:ident) => {
        impl Mat2x2Args for ($a,$b,$c,$d) {
            fn make(self) -> mat2x2 {
                let (a,b,c,d) = self;
                TMat2 { elems: [[a as f32,b as f32],
                                [c as f32,d as f32]] }
            }
        }
    }
    ;
}

impl_Mat2x2Args_for!(f32 copy)
impl_Mat2x2Args_for!(int,int,int,int)
impl_Mat2x2Args_for!(int,int,int,f32)
impl_Mat2x2Args_for!(int,int,f32,int)
impl_Mat2x2Args_for!(int,int,f32,f32)
impl_Mat2x2Args_for!(int,f32,int,int)
impl_Mat2x2Args_for!(int,f32,int,f32)
impl_Mat2x2Args_for!(int,f32,f32,int)
impl_Mat2x2Args_for!(int,f32,f32,f32)
impl_Mat2x2Args_for!(f32,int,int,int)
impl_Mat2x2Args_for!(f32,int,int,f32)
impl_Mat2x2Args_for!(f32,int,f32,int)
impl_Mat2x2Args_for!(f32,int,f32,f32)
impl_Mat2x2Args_for!(f32,f32,int,int)
impl_Mat2x2Args_for!(f32,f32,int,f32)
impl_Mat2x2Args_for!(f32,f32,f32,int)
impl_Mat2x2Args_for!(f32,f32,f32,f32)

double_dispatch_T!{Mul for TMat2 mul via TMat2MulRHS rev_mul}
double_dispatch_T!{Div for TMat2 div via TMat2DivRHS rev_div}

impl<T:Num> TMat2MulRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let l = &lhs.elems;
        let r = &self.elems;
        let c00 = l[0][0] * r[0][0] + l[0][1] * r[1][0];
        let c01 = l[0][0] * r[0][1] + l[0][1] * r[1][1];
        let c10 = l[1][0] * r[0][0] + l[1][1] * r[1][0];
        let c11 = l[1][0] * r[0][1] + l[1][1] * r[1][1];

        TMat2 { elems: [[c00, c01],
                        [c10, c11]] }
    }
}

impl<T:Num> TMat2MulRHS<T,TVec2<T>> for TVec2<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TVec2<T> {
        let a00 = &lhs.elems[0][0]; let a01 = &lhs.elems[0][1];
        let a10 = &lhs.elems[1][0]; let a11 = &lhs.elems[1][1];
        TVec2{ x: *a00 * self.x + *a01 * self.y,
               y: *a10 * self.x + *a11 * self.y }
    }
}

impl<T:Num> TVec2MulRHS<T,TVec2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &TVec2<T>) -> TVec2<T> {
        let b00 = &self.elems[0][0]; let b01 = &self.elems[0][1];
        let b10 = &self.elems[1][0]; let b11 = &self.elems[1][1];
        TVec2{ x: lhs.x * *b00 + lhs.y * *b10,
               y: lhs.x * *b01 + lhs.y * *b11 }
    }
}

impl<T:Num> TMat2MulRHS<T,TMat2<T>> for S<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let S(ref f) = *self;
        lhs.map(|x|*x * *f)
    }
}

impl<T:Num> TMat2DivRHS<T,TMat2<T>> for S<T> {
    fn rev_div(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let S(ref f) = *self;
        lhs.map(|x|*x / *f)
    }
}

impl<T:Num> SMulRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &S<T>) -> TMat2<T> {
        let S(ref f) = *lhs;
        self.map(|x|*f * *x)
    }
}

impl<T:Num> SDivRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_div(&self, lhs: &S<T>) -> TMat2<T> {
        let S(ref f) = *lhs;
        self.map(|x|*f / *x)
    }
}

#[cfg(test)]
mod mat2x2_tests {
    #![allow(uppercase_variables)]

    use super::{mat2x2,mat2};
    use super::{inverse};
    use super::{Matrix};

    use src::operators::{EpsilonEq};
    use src::typedefs::{vec2};
    use src::vector::{vec2};
    use src::scalar::S;

    #[test]
    fn test_operators() {
        let l = mat2x2(1.0f32);
        let m = mat2x2(1.0f32);
        let u = vec2(1.0f32);
        let v = vec2(1.0f32);
        let x = S(1.0f32);

        let a : vec2 = m * u;
        let b : vec2 = v * m;
        let n : mat2x2 = x / m;
        let o : mat2x2 = m / x;
        let p : mat2x2 = x * m;
        let q : mat2x2 = m * x;

        let _ = (a,b,n,o,p);
        assert_eq!(m, q);
        assert_eq!(m, l);
    }

    #[test]
    fn test_inverse() {
        let Matrix = mat2((1, 2, 3, 4));
        let Inverse = inverse(&Matrix);
        let Identity = Matrix * Inverse;

        assert!(Identity.row(0).epsilon_eq(&vec2((1f32, 0f32)), &vec2(0.01f32)));
    }
}
<commit_msg>Finished remainder of core_type_mat2x2 tests.<commit_after>pub use src::typedefs::{vec2,mat2x2};

use src::vector::{TVec2,TVec2MulRHS};
use src::scalar::{S,SMulRHS,SDivRHS};
use std::fmt;

trait Matrix<RowVec,ColVec> {
    fn col(&self, i: uint) -> ColVec;
    fn row(&self, j: uint) -> RowVec;
}

trait Invertible {
    // (should this be Result<Self> ?)
    // (also, should this take self by value?)
    fn inverse(&self) -> Self;
}

pub fn inverse<M:Invertible>(m: &M) -> M { m.inverse() }

pub struct TMat2<T> {
    elems: [[T, ..2], ..2]
}
#[deriving(Eq,Show)]
pub struct TMat3<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4<T>; // FIXME

#[deriving(Eq,Show)]
pub struct TMat2x3<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat2x4<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat3x2<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat3x4<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4x2<T>; // FIXME
#[deriving(Eq,Show)]
pub struct TMat4x3<T>; // FIXME

impl<T:Clone> Matrix<TVec2<T>,TVec2<T>> for TMat2<T> {
    fn col(&self, i: uint) -> TVec2<T> {
        assert!(i <= 1);
        TVec2 { x: self.elems[0][i].clone(), y: self.elems[1][i].clone() }
    }
    fn row(&self, j: uint) -> TVec2<T> {
        assert!(j <= 1);
        TVec2 { x: self.elems[j][0].clone(), y: self.elems[j][1].clone() }
    }
}

impl<T:Num> Invertible for TMat2<T> {
    fn inverse(&self) -> TMat2<T> {
        #![allow(uppercase_variables)]
        use std::num::One;
        let m = &self.elems;
        let one : T = One::one();
        let OneOverDeterminant = one / (m[0][0] * m[1][1] - m[1][0] * m[0][1]);
        TMat2 { elems: [[m[1][1] * OneOverDeterminant, m[0][1] * OneOverDeterminant],
                        [m[1][0] * OneOverDeterminant, m[0][0] * OneOverDeterminant]] }
    }
}

impl<T:fmt::Show> fmt::Show for TMat2<T> {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        try!(write!(f, "["));
        try!(self.elems[0].as_slice().fmt(f));
        try!(write!(f, "\n "));
        write!(f, "]")
    }
}

impl<T:Eq> Eq for TMat2<T> {
    fn eq(&self, rhs: &TMat2<T>) -> bool {
        self.elems[0] == rhs.elems[0] && self.elems[1] == rhs.elems[1]
    }
}

impl<T> TMat2<T> {
    fn map<U>(&self, f: |&T| -> U) -> TMat2<U> {
        TMat2 { elems: [[f(&self.elems[0][0]), f(&self.elems[0][1])],
                        [f(&self.elems[1][0]), f(&self.elems[1][1])]] }
    }
}

pub trait Mat2x2Args { fn make(self) -> mat2x2; }

pub fn mat2x2<Args:Mat2x2Args>(args: Args) -> mat2x2 { args.make() }
pub fn mat2<Args:Mat2x2Args>(args: Args) -> mat2x2 { args.make() }

macro_rules! impl_Mat2x2Args_for {
    ($a:ident copy) => {
        impl Mat2x2Args for $a {
            fn make(self) -> mat2x2 {
                let x = self;
                TMat2 { elems: [[x as f32,x as f32],
                                [x as f32,x as f32]] }
            }
        }
    }
    ;
    ($a:ident,$b:ident,$c:ident,$d:ident) => {
        impl Mat2x2Args for ($a,$b,$c,$d) {
            fn make(self) -> mat2x2 {
                let (a,b,c,d) = self;
                TMat2 { elems: [[a as f32,b as f32],
                                [c as f32,d as f32]] }
            }
        }
        impl Mat2x2Args for (($a,$b),$c,$d) {
            fn make(self) -> mat2x2 {
                let ((a,b),c,d) = self;
                TMat2 { elems: [[a as f32,b as f32],
                                [c as f32,d as f32]] }
            }
        }
        impl Mat2x2Args for ($a,$b,($c,$d)) {
            fn make(self) -> mat2x2 {
                let (a,b,(c,d)) = self;
                TMat2 { elems: [[a as f32,b as f32],
                                [c as f32,d as f32]] }
            }
        }
        impl Mat2x2Args for (($a,$b),($c,$d)) {
            fn make(self) -> mat2x2 {
                let ((a,b),(c,d)) = self;
                TMat2 { elems: [[a as f32,b as f32],
                                [c as f32,d as f32]] }
            }
        }
    }
    ;
    ($a:ident 2,$b:ident,$c:ident) => {
        impl Mat2x2Args for ($a,$b,$c) {
            fn make(self) -> mat2x2 {
                let (a,b,c) = self;
                TMat2 { elems: [[a.x as f32,a.y as f32],
                                [b as f32,  c as f32]] }
            }
        }
        impl Mat2x2Args for ($a,($b,$c)) {
            fn make(self) -> mat2x2 {
                let (a,(b,c)) = self;
                TMat2 { elems: [[a.x as f32,a.y as f32],
                                [b as f32,  c as f32]] }
            }
        }
    }
    ;
    ($a:ident,$b:ident,$c:ident 2) => {
        impl Mat2x2Args for ($a,$b,$c) {
            fn make(self) -> mat2x2 {
                let (a,b,c) = self;
                TMat2 { elems: [[a as f32,  b as f32],
                                [c.x as f32,c.y as f32]] }
            }
        }
        impl Mat2x2Args for (($a,$b),$c) {
            fn make(self) -> mat2x2 {
                let ((a,b),c) = self;
                TMat2 { elems: [[a as f32,  b as f32],
                                [c.x as f32,c.y as f32]] }
            }
        }
    }
    ;
    ($a:ident 2,$b:ident 2) => {
        impl Mat2x2Args for ($a,$b) {
            fn make(self) -> mat2x2 {
                let (a,b) = self;
                TMat2 { elems: [[a.x as f32,a.y as f32],
                                [b.x as f32,b.y as f32]] }
            }
        }
    }
    ;
}

impl_Mat2x2Args_for!(f32 copy)
impl_Mat2x2Args_for!(int,int,int,int)
impl_Mat2x2Args_for!(int,int,int,f32)
impl_Mat2x2Args_for!(int,int,f32,int)
impl_Mat2x2Args_for!(int,int,f32,f32)
impl_Mat2x2Args_for!(int,f32,int,int)
impl_Mat2x2Args_for!(int,f32,int,f32)
impl_Mat2x2Args_for!(int,f32,f32,int)
impl_Mat2x2Args_for!(int,f32,f32,f32)
impl_Mat2x2Args_for!(f32,int,int,int)
impl_Mat2x2Args_for!(f32,int,int,f32)
impl_Mat2x2Args_for!(f32,int,f32,int)
impl_Mat2x2Args_for!(f32,int,f32,f32)
impl_Mat2x2Args_for!(f32,f32,int,int)
impl_Mat2x2Args_for!(f32,f32,int,f32)
impl_Mat2x2Args_for!(f32,f32,f32,int)
impl_Mat2x2Args_for!(f32,f32,f32,f32)
impl_Mat2x2Args_for!(vec2 2,vec2 2)
double_dispatch_T!{Mul for TMat2 mul via TMat2MulRHS rev_mul}
double_dispatch_T!{Div for TMat2 div via TMat2DivRHS rev_div}

impl<T:Num> TMat2MulRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let l = &lhs.elems;
        let r = &self.elems;
        let c00 = l[0][0] * r[0][0] + l[0][1] * r[1][0];
        let c01 = l[0][0] * r[0][1] + l[0][1] * r[1][1];
        let c10 = l[1][0] * r[0][0] + l[1][1] * r[1][0];
        let c11 = l[1][0] * r[0][1] + l[1][1] * r[1][1];

        TMat2 { elems: [[c00, c01],
                        [c10, c11]] }
    }
}

impl<T:Num> TMat2MulRHS<T,TVec2<T>> for TVec2<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TVec2<T> {
        let a00 = &lhs.elems[0][0]; let a01 = &lhs.elems[0][1];
        let a10 = &lhs.elems[1][0]; let a11 = &lhs.elems[1][1];
        TVec2{ x: *a00 * self.x + *a01 * self.y,
               y: *a10 * self.x + *a11 * self.y }
    }
}

impl<T:Num> TVec2MulRHS<T,TVec2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &TVec2<T>) -> TVec2<T> {
        let b00 = &self.elems[0][0]; let b01 = &self.elems[0][1];
        let b10 = &self.elems[1][0]; let b11 = &self.elems[1][1];
        TVec2{ x: lhs.x * *b00 + lhs.y * *b10,
               y: lhs.x * *b01 + lhs.y * *b11 }
    }
}

impl<T:Num> TMat2MulRHS<T,TMat2<T>> for S<T> {
    fn rev_mul(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let S(ref f) = *self;
        lhs.map(|x|*x * *f)
    }
}

impl<T:Num> TMat2DivRHS<T,TMat2<T>> for S<T> {
    fn rev_div(&self, lhs: &TMat2<T>) -> TMat2<T> {
        let S(ref f) = *self;
        lhs.map(|x|*x / *f)
    }
}

impl<T:Num> SMulRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_mul(&self, lhs: &S<T>) -> TMat2<T> {
        let S(ref f) = *lhs;
        self.map(|x|*f * *x)
    }
}

impl<T:Num> SDivRHS<T,TMat2<T>> for TMat2<T> {
    fn rev_div(&self, lhs: &S<T>) -> TMat2<T> {
        let S(ref f) = *lhs;
        self.map(|x|*f / *x)
    }
}

#[cfg(test)]
mod mat2x2_tests {
    #![allow(uppercase_variables)]

    use super::{mat2x2,mat2};
    use super::{inverse};
    use super::{Matrix};

    use src::operators::{EpsilonEq};
    use src::typedefs::{vec2};
    use src::vector::{vec2};
    use src::scalar::S;

    #[test]
    fn test_operators() {
        let l = mat2x2(1.0f32);
        let m = mat2x2(1.0f32);
        let u = vec2(1.0f32);
        let v = vec2(1.0f32);
        let x = S(1.0f32);

        let a : vec2 = m * u;
        let b : vec2 = v * m;
        let n : mat2x2 = x / m;
        let o : mat2x2 = m / x;
        let p : mat2x2 = x * m;
        let q : mat2x2 = m * x;

        let _ = (a,b,n,o,p);
        assert_eq!(m, q);
        assert_eq!(m, l);
    }

    #[test]
    fn test_inverse() {
        let Matrix = mat2((1, 2, 3, 4));
        let Inverse = inverse(&Matrix);
        let Identity = Matrix * Inverse;

        assert!(Identity.row(0).epsilon_eq(&vec2((1f32, 0f32)), &vec2(0.01f32)));
        assert!(Identity.row(1).epsilon_eq(&vec2((0f32, 1f32)), &vec2(0.01f32)));
    }

    #[test]
    fn test_ctr() {
        let m0 = mat2x2((vec2((0,1)),
                         vec2((2, 3))));
        let m1 = mat2x2((0, 1,
                         2, 3));
        let m2 = mat2x2(((0, 1),
                         (2, 3)));
        assert_eq!(m0, m2);
        assert_eq!(m1, m2);
    }
}
<|endoftext|>