<commit_before>extern crate gcc;

use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::process::Command;
use std::env;

fn main() {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        env::set_var("CC", "gcc");
        env::set_var("AS", "gcc -c");
        if cfg!(target_os = "linux") {
            env::set_var("AR", "ar");
        }
    } else if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
        env::set_var("CC", "cc");
        env::set_var("AS", "cc -c");
        env::set_var("AR", "ar");
    }

    let sse3 = if cfg!(target_os = "windows") {
        cfg!(feature = "sse")
    } else {
        let output = if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
            // /usr/bin/grep -o SSSE3 /var/run/dmesg.boot | /usr/bin/head -1
            Command::new("/usr/bin/grep")
                .arg("-o")
                .arg("SSE3")
                .arg("/var/run/dmesg.boot")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            // /usr/sbin/sysctl machdep.cpu.features | grep -m 1 -ow SSSE3
            Command::new("/usr/sbin/sysctl")
                .arg("machdep.cpu.features")
                .output()
                .unwrap()
        } else {
            // /bin/grep -m 1 -o ssse3 /proc/cpuinfo
            Command::new("/bin/grep")
                .arg("-m")
                .arg("1")
                .arg("-o")
                .arg("ssse3")
                .arg("/proc/cpuinfo")
                .output()
                .unwrap()
        };
        let output = std::str::from_utf8(&output.stdout[..]).unwrap().trim();

        if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") || cfg!(target_os = "macos") {
            output.contains("SSSE3")
        } else {
            output == "ssse3"
        }
    };

    let mut cflags = "-g -Wall -Wextra -Wno-unused-parameter".to_owned();
    if !cfg!(feature = "no-sse") && sse3 {
        cflags = cflags + " -mssse3";
    }
    if cfg!(feature = "no-sse") && cfg!(target_os = "macos") {
        cflags = cflags + " -march=x86-64";
    }
    cflags = cflags + " -O2";

    env::set_var("CFLAGS", cflags);

    let mut config = gcc::Config::new();
    config.file("src/c/src/bitstring.c")
          .file("src/c/src/encparams.c")
          .file("src/c/src/hash.c")
          .file("src/c/src/idxgen.c")
          .file("src/c/src/key.c")
          .file("src/c/src/mgf.c")
          .file("src/c/src/ntru.c")
          .file("src/c/src/poly.c")
          .file("src/c/src/rand.c")
          .file("src/c/src/arith.c")
          .file("src/c/src/sha1.c")
          .file("src/c/src/sha2.c")
          .file("src/c/src/nist_ctr_drbg.c")
          .file("src/c/src/rijndael.c")
          .file("src/c/src/rijndael-alg-fst.c");

    if sse3 &&
       (cfg!(target_pointer_width = "64") || cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")) {
        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha1-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        println!("Exists .s: {}", p.exists());

        let out = Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha1-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha1-mb-x86_64.o")
            .output()
            .unwrap();

        println!("Exists .o: {}", Path::new("src/c/src/sha1-mb-x86_64.o").exists());
        println!("Out: {}", std::str::from_utf8(&out.stdout[..]).unwrap().trim());

        panic!();

        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha256-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha256-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha256-mb-x86_64.o")
            .output()
            .unwrap();

        config.object("src/c/src/sha1-mb-x86_64.o").object("src/c/src/sha256-mb-x86_64.o");
    }

    config.include("src/c/src").compile("libntru.a");

    if !cfg!(feature = "no-sse") && sse3 {
        println!("cargo:rustc-cfg=SSE3")
    }
}
<commit_msg>Checking stderr<commit_after>extern crate gcc;

use std::fs::File;
use std::path::Path;
use std::io::Write;
use std::process::Command;
use std::env;

fn main() {
    if cfg!(target_os = "linux") || cfg!(target_os = "macos") || cfg!(target_os = "windows") {
        env::set_var("CC", "gcc");
        env::set_var("AS", "gcc -c");
        if cfg!(target_os = "linux") {
            env::set_var("AR", "ar");
        }
    } else if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
        env::set_var("CC", "cc");
        env::set_var("AS", "cc -c");
        env::set_var("AR", "ar");
    }

    let sse3 = if cfg!(target_os = "windows") {
        cfg!(feature = "sse")
    } else {
        let output = if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") {
            // /usr/bin/grep -o SSSE3 /var/run/dmesg.boot | /usr/bin/head -1
            Command::new("/usr/bin/grep")
                .arg("-o")
                .arg("SSE3")
                .arg("/var/run/dmesg.boot")
                .output()
                .unwrap()
        } else if cfg!(target_os = "macos") {
            // /usr/sbin/sysctl machdep.cpu.features | grep -m 1 -ow SSSE3
            Command::new("/usr/sbin/sysctl")
                .arg("machdep.cpu.features")
                .output()
                .unwrap()
        } else {
            // /bin/grep -m 1 -o ssse3 /proc/cpuinfo
            Command::new("/bin/grep")
                .arg("-m")
                .arg("1")
                .arg("-o")
                .arg("ssse3")
                .arg("/proc/cpuinfo")
                .output()
                .unwrap()
        };
        let output = std::str::from_utf8(&output.stdout[..]).unwrap().trim();

        if cfg!(target_os = "freebsd") || cfg!(target_os = "openbsd") || cfg!(target_os = "macos") {
            output.contains("SSSE3")
        } else {
            output == "ssse3"
        }
    };

    let mut cflags = "-g -Wall -Wextra -Wno-unused-parameter".to_owned();
    if !cfg!(feature = "no-sse") && sse3 {
        cflags = cflags + " -mssse3";
    }
    if cfg!(feature = "no-sse") && cfg!(target_os = "macos") {
        cflags = cflags + " -march=x86-64";
    }
    cflags = cflags + " -O2";

    env::set_var("CFLAGS", cflags);

    let mut config = gcc::Config::new();
    config.file("src/c/src/bitstring.c")
          .file("src/c/src/encparams.c")
          .file("src/c/src/hash.c")
          .file("src/c/src/idxgen.c")
          .file("src/c/src/key.c")
          .file("src/c/src/mgf.c")
          .file("src/c/src/ntru.c")
          .file("src/c/src/poly.c")
          .file("src/c/src/rand.c")
          .file("src/c/src/arith.c")
          .file("src/c/src/sha1.c")
          .file("src/c/src/sha2.c")
          .file("src/c/src/nist_ctr_drbg.c")
          .file("src/c/src/rijndael.c")
          .file("src/c/src/rijndael-alg-fst.c");

    if sse3 &&
       (cfg!(target_pointer_width = "64") || cfg!(target_os = "macos") ||
        cfg!(target_os = "windows")) {
        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha1-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha1-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        println!("Exists .s: {}", p.exists());

        let out = Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha1-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha1-mb-x86_64.o")
            .output()
            .unwrap();

        println!("Exists .o: {}", Path::new("src/c/src/sha1-mb-x86_64.o").exists());
        println!("Out: {}", std::str::from_utf8(&out.stderr[..]).unwrap().trim());

        panic!();

        let out = if cfg!(target_os = "windows") {
            Command::new("c:\\mingw\\msys\\1.0\\bin\\perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        } else {
            Command::new("/usr/bin/perl")
                .arg("src/c/src/sha256-mb-x86_64.pl")
                .arg("elf")
                .output()
                .unwrap()
        };
        let out = std::str::from_utf8(&out.stdout[..]).unwrap().trim();

        let p = Path::new("src/c/src/sha256-mb-x86_64.s");
        let mut f = File::create(&p).unwrap();
        f.write(out.as_bytes()).unwrap();

        Command::new(env::var("CC").unwrap())
            .arg("-c")
            .arg("src/c/src/sha256-mb-x86_64.s")
            .arg("-o")
            .arg("src/c/src/sha256-mb-x86_64.o")
            .output()
            .unwrap();

        config.object("src/c/src/sha1-mb-x86_64.o").object("src/c/src/sha256-mb-x86_64.o");
    }

    config.include("src/c/src").compile("libntru.a");

    if !cfg!(feature = "no-sse") && sse3 {
        println!("cargo:rustc-cfg=SSE3")
    }
}
<|endoftext|>


<commit_before>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

#![feature(core)]

use std::io::Write;
use std::simd::f64x2;
use std::sync::Arc;
use std::thread::scoped;

const ITER: i32 = 50;
const LIMIT: f64 = 2.0;
const WORKERS: usize = 16;

#[inline(always)]
fn mandelbrot<W: Write>(w: usize, mut out: W) -> std::io::Result<()> {
    assert!(WORKERS % 2 == 0);

    // Ensure w and h are multiples of 8.
    let w = (w + 7) / 8 * 8;
    let h = w;

    let chunk_size = h / WORKERS;

    // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
    let last_chunk_size = if h % WORKERS != 0 {
        chunk_size + h % WORKERS
    } else {
        chunk_size
    };

    // precalc values
    let inverse_w_doubled = 2.0 / w as f64;
    let inverse_h_doubled = 2.0 / h as f64;
    let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
    let v_consts = f64x2(1.5, 1.0);

    // A lot of this code assumes this (so do other lang benchmarks)
    assert!(w == h);
    let mut precalc_r = Vec::with_capacity(w);
    let mut precalc_i = Vec::with_capacity(h);

    let precalc_futures = (0..WORKERS).map(|i| {
        scoped(move|| {
            let mut rs = Vec::with_capacity(w / WORKERS);
            let mut is = Vec::with_capacity(w / WORKERS);

            let start = i * chunk_size;
            let end = if i == (WORKERS - 1) {
                start + last_chunk_size
            } else {
                (i + 1) * chunk_size
            };

            // This assumes w == h
            for x in start..end {
                let xf = x as f64;
                let xy = f64x2(xf, xf);

                let f64x2(r, i) = xy * v_inverses - v_consts;
                rs.push(r);
                is.push(i);
            }

            (rs, is)
        })
    }).collect::<Vec<_>>();

    for res in precalc_futures.into_iter() {
        let (rs, is) = res.join();
        precalc_r.extend(rs.into_iter());
        precalc_i.extend(is.into_iter());
    }

    assert_eq!(precalc_r.len(), w);
    assert_eq!(precalc_i.len(), h);

    let arc_init_r = Arc::new(precalc_r);
    let arc_init_i = Arc::new(precalc_i);

    let data = (0..WORKERS).map(|i| {
        let vec_init_r = arc_init_r.clone();
        let vec_init_i = arc_init_i.clone();

        scoped(move|| {
            let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);
            let init_r_slice = vec_init_r.as_slice();

            let start = i * chunk_size;
            let end = if i == (WORKERS - 1) {
                start + last_chunk_size
            } else {
                (i + 1) * chunk_size
            };

            for &init_i in vec_init_i[start..end].iter() {
                write_line(init_i, init_r_slice, &mut res);
            }

            res
        })
    }).collect::<Vec<_>>();

    try!(writeln!(&mut out, "P4\n{} {}", w, h));
    for res in data.into_iter() {
        try!(out.write_all(&res.join()));
    }
    out.flush()
}

fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
    let v_init_i : f64x2 = f64x2(init_i, init_i);
    let v_2 : f64x2 = f64x2(2.0, 2.0);
    const LIMIT_SQUARED: f64 = LIMIT * LIMIT;

    for chunk_init_r in vec_init_r.chunks(8) {
        let mut cur_byte = 0xff;
        let mut i = 0;

        while i < 8 {
            let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
            let mut cur_r = v_init_r;
            let mut cur_i = v_init_i;
            let mut r_sq = v_init_r * v_init_r;
            let mut i_sq = v_init_i * v_init_i;

            let mut b = 0;
            for _ in 0..ITER {
                let r = cur_r;
                let i = cur_i;

                cur_i = v_2 * r * i + v_init_i;
                cur_r = r_sq - i_sq + v_init_r;

                let f64x2(bit1, bit2) = r_sq + i_sq;

                if bit1 > LIMIT_SQUARED {
                    b |= 2;
                    if b == 3 { break; }
                }

                if bit2 > LIMIT_SQUARED {
                    b |= 1;
                    if b == 3 { break; }
                }

                r_sq = cur_r * cur_r;
                i_sq = cur_i * cur_i;
            }

            cur_byte = (cur_byte << 2) + b;
            i += 2;
        }

        res.push(cur_byte^-1);
    }
}

fn main() {
    let n = std::env::args_os().nth(1)
        .and_then(|s| s.into_string().ok())
        .and_then(|n| n.parse().ok())
        .unwrap_or(200);
    let stdout = std::io::stdout();
    mandelbrot(n, stdout.lock()).unwrap();
}
<commit_msg>mandelbrot: remove useless Arc<commit_after>// The Computer Language Benchmarks Game
// http://benchmarksgame.alioth.debian.org/
//
// contributed by the Rust Project Developers
// contributed by TeXitoi

#![feature(core)]

use std::io::Write;
use std::simd::f64x2;
use std::thread::scoped;

const ITER: i32 = 50;
const LIMIT: f64 = 2.0;
const WORKERS: usize = 16;

#[inline(always)]
fn mandelbrot<W: Write>(w: usize, mut out: W) -> std::io::Result<()> {
    assert!(WORKERS % 2 == 0);

    // Ensure w and h are multiples of 8.
    let w = (w + 7) / 8 * 8;
    let h = w;

    let chunk_size = h / WORKERS;

    // Account for remainders in workload division, e.g. 1000 / 16 = 62.5
    let last_chunk_size = if h % WORKERS != 0 {
        chunk_size + h % WORKERS
    } else {
        chunk_size
    };

    // precalc values
    let inverse_w_doubled = 2.0 / w as f64;
    let inverse_h_doubled = 2.0 / h as f64;
    let v_inverses = f64x2(inverse_w_doubled, inverse_h_doubled);
    let v_consts = f64x2(1.5, 1.0);

    // A lot of this code assumes this (so do other lang benchmarks)
    assert!(w == h);
    let mut precalc_r = Vec::with_capacity(w);
    let mut precalc_i = Vec::with_capacity(h);

    let precalc_futures = (0..WORKERS).map(|i| {
        scoped(move|| {
            let mut rs = Vec::with_capacity(w / WORKERS);
            let mut is = Vec::with_capacity(w / WORKERS);

            let start = i * chunk_size;
            let end = if i == (WORKERS - 1) {
                start + last_chunk_size
            } else {
                (i + 1) * chunk_size
            };

            // This assumes w == h
            for x in start..end {
                let xf = x as f64;
                let xy = f64x2(xf, xf);

                let f64x2(r, i) = xy * v_inverses - v_consts;
                rs.push(r);
                is.push(i);
            }

            (rs, is)
        })
    }).collect::<Vec<_>>();

    for res in precalc_futures.into_iter() {
        let (rs, is) = res.join();
        precalc_r.extend(rs.into_iter());
        precalc_i.extend(is.into_iter());
    }

    assert_eq!(precalc_r.len(), w);
    assert_eq!(precalc_i.len(), h);

    let vec_init_r = &precalc_r;
    let vec_init_i = &precalc_i;

    let data = (0..WORKERS).map(|i| {
        scoped(move|| {
            let mut res: Vec<u8> = Vec::with_capacity((chunk_size * w) / 8);

            let start = i * chunk_size;
            let end = if i == (WORKERS - 1) {
                start + last_chunk_size
            } else {
                (i + 1) * chunk_size
            };

            for &init_i in vec_init_i[start..end].iter() {
                write_line(init_i, &vec_init_r, &mut res);
            }

            res
        })
    }).collect::<Vec<_>>();

    try!(writeln!(&mut out, "P4\n{} {}", w, h));
    for res in data.into_iter() {
        try!(out.write_all(&res.join()));
    }
    out.flush()
}

fn write_line(init_i: f64, vec_init_r: &[f64], res: &mut Vec<u8>) {
    let v_init_i : f64x2 = f64x2(init_i, init_i);
    let v_2 : f64x2 = f64x2(2.0, 2.0);
    const LIMIT_SQUARED: f64 = LIMIT * LIMIT;

    for chunk_init_r in vec_init_r.chunks(8) {
        let mut cur_byte = 0xff;
        let mut i = 0;

        while i < 8 {
            let v_init_r = f64x2(chunk_init_r[i], chunk_init_r[i + 1]);
            let mut cur_r = v_init_r;
            let mut cur_i = v_init_i;
            let mut r_sq = v_init_r * v_init_r;
            let mut i_sq = v_init_i * v_init_i;

            let mut b = 0;
            for _ in 0..ITER {
                let r = cur_r;
                let i = cur_i;

                cur_i = v_2 * r * i + v_init_i;
                cur_r = r_sq - i_sq + v_init_r;

                let f64x2(bit1, bit2) = r_sq + i_sq;

                if bit1 > LIMIT_SQUARED {
                    b |= 2;
                    if b == 3 { break; }
                }

                if bit2 > LIMIT_SQUARED {
                    b |= 1;
                    if b == 3 { break; }
                }

                r_sq = cur_r * cur_r;
                i_sq = cur_i * cur_i;
            }

            cur_byte = (cur_byte << 2) + b;
            i += 2;
        }

        res.push(cur_byte^-1);
    }
}

fn main() {
    let n = std::env::args_os().nth(1)
        .and_then(|s| s.into_string().ok())
        .and_then(|n| n.parse().ok())
        .unwrap_or(200);
    let stdout = std::io::stdout();
    mandelbrot(n, stdout.lock()).unwrap();
}
<|endoftext|>


<commit_before>use super::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(_) => panic!("Categories can't be mentioned"),
        }
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserIdParseError {
    InvalidFormat,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserIdParseError {
    fn description(&self) -> &str {
        use self::UserIdParseError::*;

        match *self {
            InvalidFormat => "invalid user id format",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for UserId {
    type Err = UserIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        Ok(match utils::parse_username(s) {
            Some(id) => UserId(id),
            None => s.parse::<u64>().map(UserId).map_err(|_| UserIdParseError::InvalidFormat)?,
        })
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleParseError {
    NotPresentInCache,
    InvalidRole,
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl fmt::Display for RoleParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl StdError for RoleParseError {
    fn description(&self) -> &str {
        use self::RoleParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
            InvalidRole => "invalid role",
        }
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Role {
    type Err = RoleParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_role(s) {
            Some(x) => match RoleId(x).find() {
                Some(user) => Ok(user),
                _ => Err(RoleParseError::NotPresentInCache),
            },
            _ => Err(RoleParseError::InvalidRole),
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum RoleIdParseError {
    InvalidFormat,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for RoleIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for RoleIdParseError {
    fn description(&self) -> &str {
        use self::RoleIdParseError::*;

        match *self {
            InvalidFormat => "invalid role id format",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for RoleId {
    type Err = RoleIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        Ok(match utils::parse_role(s) {
            Some(id) => RoleId(id),
            None => s.parse::<u64>().map(RoleId).map_err(|_| RoleIdParseError::InvalidFormat)?,
        })
    }
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum ChannelIdParseError {
    InvalidFormat,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for ChannelIdParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for ChannelIdParseError {
    fn description(&self) -> &str {
        use self::ChannelIdParseError::*;

        match *self {
            InvalidFormat => "invalid channel id format",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for ChannelId {
    type Err = ChannelIdParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        Ok(match utils::parse_channel(s) {
            Some(channel) => ChannelId(channel),
            None => s.parse::<u64>().map(ChannelId).map_err(|_| ChannelIdParseError::InvalidFormat)?,
        })
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum ChannelParseError {
    NotPresentInCache,
    InvalidChannel,
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl fmt::Display for ChannelParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl StdError for ChannelParseError {
    fn description(&self) -> &str {
        use self::ChannelParseError::*;

        match *self {
            NotPresentInCache => "not present in cache",
            InvalidChannel => "invalid channel",
        }
    }
}

#[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
impl FromStr for Channel {
    type Err = ChannelParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_channel(s) {
            Some(x) => match ChannelId(x).find() {
                Some(channel) => Ok(channel),
                _ => Err(ChannelParseError::NotPresentInCache),
            },
            _ => Err(ChannelParseError::InvalidChannel),
        }
    }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<commit_msg>Use a macro to generate FromStr impls<commit_after>use super::*;
use internal::RwLockExt;

#[cfg(all(feature = "model", feature = "utils"))]
use std::error::Error as StdError;
#[cfg(all(feature = "model", feature = "utils"))]
use std::result::Result as StdResult;
#[cfg(all(feature = "model", feature = "utils"))]
use std::str::FromStr;
#[cfg(all(feature = "model", feature = "utils"))]
use std::fmt;
#[cfg(all(feature = "model", any(feature = "cache", feature = "utils")))]
use utils;

/// Allows something - such as a channel or role - to be mentioned in a message.
pub trait Mentionable {
    /// Creates a mentionable string, that will be able to notify and/or create
    /// a link to the item.
    fn mention(&self) -> String;
}

impl Mentionable for ChannelId {
    fn mention(&self) -> String { format!("<#{}>", self.0) }
}

impl Mentionable for Channel {
    fn mention(&self) -> String {
        match *self {
            Channel::Guild(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Private(ref x) => format!("<#{}>", x.with(|x| x.id.0)),
            Channel::Group(ref x) => format!("<#{}>", x.with(|x| x.channel_id.0)),
            Channel::Category(_) => panic!("Categories can't be mentioned"),
        }
    }
}

impl Mentionable for Emoji {
    fn mention(&self) -> String { format!("<:{}:{}>", self.name, self.id.0) }
}

impl Mentionable for Member {
    fn mention(&self) -> String { format!("<@{}>", self.user.with(|u| u.id.0)) }
}

impl Mentionable for RoleId {
    fn mention(&self) -> String { format!("<@&{}>", self.0) }
}

impl Mentionable for Role {
    fn mention(&self) -> String { format!("<@&{}>", self.id.0) }
}

impl Mentionable for UserId {
    fn mention(&self) -> String { format!("<@{}>", self.0) }
}

impl Mentionable for User {
    fn mention(&self) -> String { format!("<@{}>", self.id.0) }
}

#[cfg(all(feature = "model", feature = "utils"))]
#[derive(Debug)]
pub enum UserParseError {
    InvalidUsername,
    Rest(Box<Error>),
}

#[cfg(all(feature = "model", feature = "utils"))]
impl fmt::Display for UserParseError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl StdError for UserParseError {
    fn description(&self) -> &str {
        use self::UserParseError::*;

        match *self {
            InvalidUsername => "invalid username",
            Rest(_) => "could not fetch",
        }
    }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for User {
    type Err = UserParseError;

    fn from_str(s: &str) -> StdResult<Self, Self::Err> {
        match utils::parse_username(s) {
            Some(x) => UserId(x as u64)
                .get()
                .map_err(|e| UserParseError::Rest(Box::new(e))),
            _ => Err(UserParseError::InvalidUsername),
        }
    }
}

macro_rules! impl_from_str {
    (id: $($id:tt, $err:ident;)*) => {
        $(
            #[cfg(all(feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                InvalidFormat,
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        InvalidFormat => "invalid id format",
                    }
                }
            }

            #[cfg(all(feature = "model", feature = "utils"))]
            impl FromStr for $id {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    Ok(match utils::parse_username(s) {
                        Some(id) => $id(id),
                        None => s.parse::<u64>().map($id).map_err(|_| $err::InvalidFormat)?,
                    })
                }
            }
        )*
    };

    (struct: $($struct:ty, $id:tt, $err:ident, $invalid_variant:tt, $parse_fn:ident, $desc:expr;)*) => {
        $(
            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            #[derive(Debug)]
            pub enum $err {
                NotPresentInCache,
                $invalid_variant,
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl fmt::Display for $err {
                fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.description()) }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl StdError for $err {
                fn description(&self) -> &str {
                    use self::$err::*;

                    match *self {
                        NotPresentInCache => "not present in cache",
                        $invalid_variant => $desc,
                    }
                }
            }

            #[cfg(all(feature = "cache", feature = "model", feature = "utils"))]
            impl FromStr for $struct {
                type Err = $err;

                fn from_str(s: &str) -> StdResult<Self, Self::Err> {
                    match utils::$parse_fn(s) {
                        Some(x) => match $id(x).find() {
                            Some(user) => Ok(user),
                            _ => Err($err::NotPresentInCache),
                        },
                        _ => Err($err::$invalid_variant),
                    }
                }
            }
        )*
    };
}

impl_from_str! { id:
    UserId, UserIdParseError;
    RoleId, RoleIdParseError;
    ChannelId, ChannelIdParseError;
}

impl_from_str! { struct:
    Channel, ChannelId, ChannelParseError, InvalidChannel, parse_channel, "invalid channel";
    Role, RoleId, RoleParseError, InvalidRole, parse_role, "invalid role";
}

/// A version of an emoji used only when solely the Id and name are known.
#[derive(Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)]
pub struct EmojiIdentifier {
    /// The Id of the emoji.
    pub id: EmojiId,
    /// The name of the emoji. It must be at least 2 characters long and can
    /// only contain alphanumeric characters and underscores.
    pub name: String,
}

#[cfg(all(feature = "model", feature = "utils"))]
impl EmojiIdentifier {
    /// Generates a URL to the emoji's image.
    #[inline]
    pub fn url(&self) -> String { format!(cdn!("/emojis/{}.png"), self.id) }
}

#[cfg(all(feature = "model", feature = "utils"))]
impl FromStr for EmojiIdentifier {
    type Err = ();

    fn from_str(s: &str) -> StdResult<Self, ()> { utils::parse_emoji(s).ok_or_else(|| ()) }
}

/// A component that was affected during a service incident.
///
/// This is pulled from the Discord status page.
#[derive(Clone, Debug, Deserialize)]
pub struct AffectedComponent {
    pub name: String,
}

/// An incident retrieved from the Discord status page.
///
/// This is not necessarily a representation of an ongoing incident.
#[derive(Clone, Debug, Deserialize)]
pub struct Incident {
    pub created_at: String,
    pub id: String,
    pub impact: String,
    pub incident_updates: Vec<IncidentUpdate>,
    pub monitoring_at: Option<String>,
    pub name: String,
    pub page_id: String,
    pub resolved_at: Option<String>,
    pub short_link: String,
    pub status: String,
    pub updated_at: String,
}

/// An update to an incident from the Discord status page.
///
/// This will typically state what new information has been discovered about an
/// incident.
#[derive(Clone, Debug, Deserialize)]
pub struct IncidentUpdate {
    pub affected_components: Vec<AffectedComponent>,
    pub body: String,
    pub created_at: String,
    pub display_at: String,
    pub id: String,
    pub incident_id: String,
    pub status: IncidentStatus,
    pub updated_at: String,
}

/// The type of status update during a service incident.
#[derive(Copy, Clone, Debug, Deserialize, Hash, Eq, PartialEq, PartialOrd, Ord, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum IncidentStatus {
    Identified,
    Investigating,
    Monitoring,
    Postmortem,
    Resolved,
}

/// A Discord status maintenance message. This can be either for active
/// maintenances or for scheduled maintenances.
#[derive(Clone, Debug, Deserialize)]
pub struct Maintenance {
    pub description: String,
    pub id: String,
    pub name: String,
    pub start: String,
    pub stop: String,
}
<|endoftext|>


<commit_before>use std::str::Chars;
use std::io::Reader;
use std::str::SendStr;
use span::Span;
use std::str::Owned;

#[deriving(PartialEq, Show)]
pub enum Token {
    Str(String),
    Keyword(SendStr),
    Colon,
    Caret,
    LParen,
    RParen,
    Noop,
    Done
}

/// The lexer is the system that has any notion of an input stream. The
/// stream can come from many sources, thus, we use the Reader trait
/// that is implemented for strings, files, tcp, etc...
///
/// The lexer should also not consume the whole stream at once, as
/// that will be a bottleneck for larger input sources.
pub struct Lexer<'a> {
    source: &'a str,
    iter: Chars<'a>,
    token: Token,
    span: Span
}

impl<'a> Lexer<'a> {
    pub fn new(source: &'a str) -> Lexer<'a> {
        Lexer {
            source: source,
            iter: source.chars(),
            token: Noop,
            span: Span::new(0, 0)
        }
    }

    /// Parse and fetch the next token in the text stream.
    /// This doesn't return the token, it stores it
    /// in the lexer.
    pub fn bump(&mut self) {
        // Fetch the next char.
        let c = match self.iter.next() {
            Some(c) => c,
            None => {
                self.token = Done;
                return;
            }
        };

        match c {
            '(' => { self.token = LParen },
            ')' => { self.token = RParen },
            '^' => { self.token = Caret },
            ':' => {
                let mut keyword = String::new();
                self.iter.next().while_some(|a| {
                    if self.is_keyword(a) {
                        keyword.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                self.token = Keyword(Owned(keyword));
            },
            '"' => {
                let mut concat = String::new();
                self.iter.next().while_some(|a| {
                    if a == '"' {
                        None
                    } else {
                        concat.push_char(a);
                        self.iter.next()
                    }
                });

                self.token = Str(concat);
            },
            ch @ 'A'..'Z' | ch @ 'a'..'z' => {
                println!("{}", ch);
            },
            _ => {}
        }
    }

    /// Verify if the char is within the allowed character set for keywords. This
    /// only checks a single character at a time.
    #[inline]
    pub fn is_keyword(&self, a: char) -> bool {
        if a.is_whitespace() || a == '(' || a == ')' || a == '^' || a == ':' {
            false
        } else {
            true
        }
    }

    /// Expect a given token to come next, otherwise
    /// fail. Failing will result in a formatted
    /// error message that uses the Span and lets
    /// the user know what went wrong.
    pub fn expect(&mut self, tok: &Token) {
        if self.token == *tok {
            self.bump();
        } else {
            fail!("Expected {} but found {}", *tok, self.token);
        }
    }

    /// Optionally eat a given token. If the token is not
    /// found, this will simply return false and
    /// won't fail.
    pub fn eat(&mut self, tok: &Token) -> bool {
        if self.token == *tok {
            self.bump();
            true
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use span::Span;
    use std::str::{Slice, Owned};

    #[test]
    fn noop() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.token, Noop);
    }

    #[test]
    fn zeroed_span() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.span, Span::new(0, 0));
    }

    #[test]
    fn bump_empty() {
        let mut lexer = Lexer::new("");
        lexer.bump();
        assert_eq!(lexer.token, Done);
    }

    #[test]
    fn bump_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.token, LParen);
    }

    #[test]
    fn bump_rparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        assert_eq!(lexer.token, RParen);
    }

    #[test]
    fn bump_simple_keyword() {
        let mut lexer = Lexer::new(":foo");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo")));
    }

    #[test]
    fn bump_keyword_dash() {
        let mut lexer = Lexer::new(":foo-");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-")));
    }

    #[test]
    fn bump_keyword_dash_middle() {
        let mut lexer = Lexer::new(":foo-bar");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-bar")));
    }

    #[test]
    fn bump_string() {
        let mut lexer = Lexer::new("\"hah-w091:--:\"");
        lexer.bump();
        assert_eq!(lexer.token, Str("hah-w091:--:".to_string()));
    }

}
<commit_msg>Added identifier support<commit_after>use std::str::Chars;
use std::io::Reader;
use std::str::SendStr;
use span::Span;
use std::str::Owned;

#[deriving(PartialEq, Show)]
pub enum Token {
    Ident(String),
    Str(String),
    Keyword(SendStr),
    Colon,
    Caret,
    LParen,
    RParen,
    Noop,
    Done
}

/// The lexer is the system that has any notion of an input stream. The
/// stream can come from many sources, thus, we use the Reader trait
/// that is implemented for strings, files, tcp, etc...
///
/// The lexer should also not consume the whole stream at once, as
/// that will be a bottleneck for larger input sources.
pub struct Lexer<'a> {
    source: &'a str,
    iter: Chars<'a>,
    token: Token,
    span: Span
}

impl<'a> Lexer<'a> {
    pub fn new(source: &'a str) -> Lexer<'a> {
        Lexer {
            source: source,
            iter: source.chars(),
            token: Noop,
            span: Span::new(0, 0)
        }
    }

    /// Parse and fetch the next token in the text stream.
    /// This doesn't return the token, it stores it
    /// in the lexer.
    pub fn bump(&mut self) {
        // Fetch the next char.
        let c = match self.iter.next() {
            Some(c) => c,
            None => {
                self.token = Done;
                return;
            }
        };

        match c {
            '(' => { self.token = LParen },
            ')' => { self.token = RParen },
            '^' => { self.token = Caret },
            ':' => {
                let mut keyword = String::new();
                self.iter.next().while_some(|a| {
                    if self.is_keyword(a) {
                        keyword.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                self.token = Keyword(Owned(keyword));
            },
            '"' => {
                let mut concat = String::new();
                self.iter.next().while_some(|a| {
                    if a == '"' {
                        None
                    } else {
                        concat.push_char(a);
                        self.iter.next()
                    }
                });

                self.token = Str(concat);
            },
            // An identifier is composed of any
            // characters that contain no whitespace
            // and doesn't start with the designated
            // characters above.
            ch => {
                let mut ident = String::new();
                ident.push_char(ch);
                self.iter.next().while_some(|a| {
                    if self.is_ident(a) {
                        ident.push_char(a);
                        self.iter.next()
                    } else {
                        None
                    }
                });

                self.token = Ident(ident);
            }
        }
    }

    /// Determine if a char is allowed within an identifier.
    pub fn is_ident(&self, ch: char) -> bool {
        if ch.is_whitespace() || ch == ':' || ch == '(' || ch == ')' || ch == '"'
            || ch == '@' || ch == '!' {
            false
        } else {
            true
        }
    }

    /// Verify if the char is within the allowed character set for keywords. This
    /// only checks a single character at a time.
    #[inline]
    pub fn is_keyword(&self, a: char) -> bool {
        if a.is_whitespace() || a == '(' || a == ')' || a == '^' || a == ':' {
            false
        } else {
            true
        }
    }

    /// Expect a given token to come next, otherwise
    /// fail. Failing will result in a formatted
    /// error message that uses the Span and lets
    /// the user know what went wrong.
    pub fn expect(&mut self, tok: &Token) {
        if self.token == *tok {
            self.bump();
        } else {
            fail!("Expected {} but found {}", *tok, self.token);
        }
    }

    /// Optionally eat a given token. If the token is not
    /// found, this will simply return false and
    /// won't fail.
    pub fn eat(&mut self, tok: &Token) -> bool {
        if self.token == *tok {
            self.bump();
            true
        } else {
            false
        }
    }
}

#[cfg(test)]
mod test {
    use super::*;
    use span::Span;
    use std::str::{Slice, Owned};

    #[test]
    fn noop() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.token, Noop);
    }

    #[test]
    fn zeroed_span() {
        let lexer = Lexer::new("foo");
        assert_eq!(lexer.span, Span::new(0, 0));
    }

    #[test]
    fn bump_empty() {
        let mut lexer = Lexer::new("");
        lexer.bump();
        assert_eq!(lexer.token, Done);
    }

    #[test]
    fn bump_lparen() {
        let mut lexer = Lexer::new("(");
        lexer.bump();
        assert_eq!(lexer.token, LParen);
    }

    #[test]
    fn bump_rparen() {
        let mut lexer = Lexer::new(")");
        lexer.bump();
        assert_eq!(lexer.token, RParen);
    }

    #[test]
    fn bump_simple_keyword() {
        let mut lexer = Lexer::new(":foo");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo")));
    }

    #[test]
    fn bump_keyword_dash() {
        let mut lexer = Lexer::new(":foo-");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-")));
    }

    #[test]
    fn bump_keyword_dash_middle() {
        let mut lexer = Lexer::new(":foo-bar");
        lexer.bump();
        assert_eq!(lexer.token, Keyword(Slice("foo-bar")));
    }

    #[test]
    fn bump_string() {
        let mut lexer = Lexer::new("\"hah-w091:--:\"");
        lexer.bump();
        assert_eq!(lexer.token, Str("hah-w091:--:".to_string()));
    }

    #[test]
    fn bump_ident() {
        let mut lexer = Lexer::new("foo-bar-&#^");
        lexer.bump();
        assert_eq!(lexer.token, Ident("foo-bar-&#^".to_string()));
    }
}
<|endoftext|>


<commit_before>use {node, routing, time, hash};
use std::collections::VecDeque;
use std::str::FromStr;
use std::net;
use node::receptions;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   assert!(alpha.bootstrap_until(beta_seed, 1).is_ok());

   let beta_receptions = beta.receptions()
      .during(span)
      .from(alpha.id().clone())
      .of_kind(receptions::KindFilter::Ping);

   // Alpha pings beta.
   assert!(alpha.ping(&beta.resources.id).is_ok());
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new().unwrap();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {

   let mut nodes = simulated_network(30);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
fn finding_on_simulated_unresponsive_network() {

   let mut nodes = simulated_network(30);
   nodes.drain(10..20);
   assert_eq!(nodes.len(), 20);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
#[ignore]
fn finding_a_nonexisting_node_in_a_simulated_network_times_out() {

   let mut nodes = simulated_network(30);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();

   let random_hash = hash::SubotaiHash::random();
   assert!(head.find_node(&random_hash).is_err());
}

fn simulated_network(nodes: usize) -> VecDeque<node::Node> {
   let nodes: VecDeque<node::Node> = (0..nodes).map(|_| { node::Node::new().unwrap() }).collect();
   {
      let origin = nodes.front().unwrap();
      // Initial handshake pass
      for node in nodes.iter().skip(1) {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }

      // Actual bootstrapping
      for node in nodes.iter().skip(1) {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }
   nodes
}

#[test]
fn updating_table_with_full_bucket_starts_the_conflict_resolution_mechanism()
{
   let node = node::Node::new().unwrap();
   node.resources.table.fill_bucket(8, routing::K_FACTOR as u8); // Bucket completely full

   let mut id = node.id().clone();
   id.flip_bit(8);
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id);

   node.resources.update_table(info);
   assert_eq!(node.resources.conflicts.lock().unwrap().len(), 1);
}

#[test]
fn generating_a_conflict_causes_a_ping_to_the_evicted_node()
{
   let alpha = node::Node::new().unwrap();
   let beta = node::Node::new().unwrap();
   alpha.resources.update_table(beta.local_info());

   let index = alpha.resources.table.bucket_for_node(beta.id());

   // We fill the bucket corresponding to Beta until we are ready to cause a conflict.
   alpha.resources.table.fill_bucket(index, (routing::K_FACTOR -1) as u8);

   // We expect a ping to beta
   let pings = beta.receptions()
      .of_kind(receptions::KindFilter::Ping)
      .during(time::Duration::seconds(2));

   // Adding a new node causes a conflict.
   let mut id = beta.id().clone();
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id);
   alpha.resources.update_table(info);

   assert_eq!(pings.count(), 1);
}

#[test]
fn generating_too_many_conflicts_causes_the_node_to_enter_defensive_state()
{
   let node = node::Node::new().unwrap();

   for index in 0..(routing::K_FACTOR + routing::MAX_CONFLICTS) {
      let mut id = node.id().clone();
      id.flip_bit(140); // Arbitrary bucket
      id.raw[0] = index as u8;
      let info = node_info_no_net(id);
      node.resources.update_table(info);
   }

   let state = *node.resources.state.read().unwrap();
   match state {
      node::State::Defensive => (),
      _ => panic!(),
   }

   // Trying to add new conflictive nodes while in defensive state will fail.
   let mut id = node.id().clone();
   id.flip_bit(140); // Arbitrary bucket
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id.clone());

   node.resources.update_table(info);
   assert!(node.resources.table.specific_node(&id).is_none());

   // However, if they would fall in a different bucket, it's ok.
   id.flip_bit(155);
   let info = node_info_no_net(id.clone());
   node.resources.update_table(info);
   assert!(node.resources.table.specific_node(&id).is_some());
}

#[test]
fn remote_key_value_storage()
{
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();

   assert!(alpha.bootstrap_until(beta.local_info(), 1).is_ok());

   let key = hash::SubotaiHash::random();
   let value = hash::SubotaiHash::random();
   let mut receptions =
      beta.receptions()
          .of_kind(receptions::KindFilter::Store)
          .during(time::Duration::seconds(1));

   alpha.resources.store_remotely(beta.id(), key.clone(), value.clone()).unwrap();
   assert!(receptions.next().is_some());

   let retrieved_value = beta.resources.storage.get(&key).unwrap();
   assert_eq!(value, retrieved_value);
}

#[test]
fn node_probing_in_simulated_network()
{
   let mut nodes = simulated_network(40);
   // We manually collect the info tags of all nodes.
   let mut info_nodes: Vec<routing::NodeInfo> = nodes
      .iter()
      .map(|ref node| node.local_info())
      .collect();

   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   let probe_results = head.resources.probe_node(tail.id()).unwrap();

   // We sort our manual collection by distance to the tail node.
   info_nodes.sort_by(|ref info_a, ref info_b| (&info_a.id ^ tail.id()).cmp(&(&info_b.id ^ tail.id())));
   info_nodes.truncate(routing::K_FACTOR); // This guarantees us the closest ids to the tail

   assert_eq!(info_nodes.len(), probe_results.len());
   for (a, b) in probe_results.iter().zip(info_nodes.iter()) {
      assert_eq!(a.id, b.id);
   }
}

fn node_info_no_net(id : hash::SubotaiHash) -> routing::NodeInfo {
   routing::NodeInfo {
      id : id,
      address : net::SocketAddr::from_str("0.0.0.0:0").unwrap(),
   }
}
<commit_msg>Probing in unresponsive networks<commit_after>use {node, routing, time, hash};
use std::collections::VecDeque;
use std::str::FromStr;
use std::net;
use node::receptions;

pub const POLL_FREQUENCY_MS: u64 = 50;
pub const TRIES: u8 = 5;

#[test]
fn node_ping() {
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();
   let beta_seed = beta.local_info();
   let span = time::Duration::seconds(1);

   // Bootstrapping alpha:
   assert!(alpha.bootstrap_until(beta_seed, 1).is_ok());

   let beta_receptions = beta.receptions()
      .during(span)
      .from(alpha.id().clone())
      .of_kind(receptions::KindFilter::Ping);

   // Alpha pings beta.
   assert!(alpha.ping(&beta.resources.id).is_ok());
   assert_eq!(1, beta_receptions.count());
}

#[test]
fn reception_iterator_times_out_correctly() {
   let alpha = node::Node::new().unwrap();
   let span = time::Duration::seconds(1);
   let maximum = time::Duration::seconds(3);
   let receptions = alpha.receptions().during(span);

   let before = time::SteadyTime::now();

   // nothing is happening, so this should time out in around a second (not necessarily precise)
   assert_eq!(0, receptions.count());

   let after = time::SteadyTime::now();

   assert!(after - before < maximum);
}

#[test]
fn bootstrapping_and_finding_on_simulated_network() {

   let mut nodes = simulated_network(30);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
fn finding_on_simulated_unresponsive_network() {

   let mut nodes = simulated_network(30);
   nodes.drain(10..20);
   assert_eq!(nodes.len(), 20);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();

   assert_eq!(head.find_node(tail.id()).unwrap().id, tail.local_info().id);
}

#[test]
#[ignore]
fn finding_a_nonexisting_node_in_a_simulated_network_times_out() {

   let mut nodes = simulated_network(30);

   // Head finds tail in a few steps.
   let head = nodes.pop_front().unwrap();

   let random_hash = hash::SubotaiHash::random();
   assert!(head.find_node(&random_hash).is_err());
}

fn simulated_network(nodes: usize) -> VecDeque<node::Node> {
   let nodes: VecDeque<node::Node> = (0..nodes).map(|_| { node::Node::new().unwrap() }).collect();
   {
      let origin = nodes.front().unwrap();
      // Initial handshake pass
      for node in nodes.iter().skip(1) {
         assert!(node.bootstrap_until(origin.local_info(), 1).is_ok());
      }

      // Actual bootstrapping
      for node in nodes.iter().skip(1) {
         assert!(node.bootstrap(origin.local_info()).is_ok());
      }
   }
   nodes
}

#[test]
fn updating_table_with_full_bucket_starts_the_conflict_resolution_mechanism()
{
   let node = node::Node::new().unwrap();
   node.resources.table.fill_bucket(8, routing::K_FACTOR as u8); // Bucket completely full

   let mut id = node.id().clone();
   id.flip_bit(8);
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id);

   node.resources.update_table(info);
   assert_eq!(node.resources.conflicts.lock().unwrap().len(), 1);
}

#[test]
fn generating_a_conflict_causes_a_ping_to_the_evicted_node()
{
   let alpha = node::Node::new().unwrap();
   let beta = node::Node::new().unwrap();
   alpha.resources.update_table(beta.local_info());

   let index = alpha.resources.table.bucket_for_node(beta.id());

   // We fill the bucket corresponding to Beta until we are ready to cause a conflict.
   alpha.resources.table.fill_bucket(index, (routing::K_FACTOR -1) as u8);

   // We expect a ping to beta
   let pings = beta.receptions()
      .of_kind(receptions::KindFilter::Ping)
      .during(time::Duration::seconds(2));

   // Adding a new node causes a conflict.
   let mut id = beta.id().clone();
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id);
   alpha.resources.update_table(info);

   assert_eq!(pings.count(), 1);
}

#[test]
fn generating_too_many_conflicts_causes_the_node_to_enter_defensive_state()
{
   let node = node::Node::new().unwrap();

   for index in 0..(routing::K_FACTOR + routing::MAX_CONFLICTS) {
      let mut id = node.id().clone();
      id.flip_bit(140); // Arbitrary bucket
      id.raw[0] = index as u8;
      let info = node_info_no_net(id);
      node.resources.update_table(info);
   }

   let state = *node.resources.state.read().unwrap();
   match state {
      node::State::Defensive => (),
      _ => panic!(),
   }

   // Trying to add new conflictive nodes while in defensive state will fail.
   let mut id = node.id().clone();
   id.flip_bit(140); // Arbitrary bucket
   id.raw[0] = 0xFF;
   let info = node_info_no_net(id.clone());

   node.resources.update_table(info);
   assert!(node.resources.table.specific_node(&id).is_none());

   // However, if they would fall in a different bucket, it's ok.
   id.flip_bit(155);
   let info = node_info_no_net(id.clone());
   node.resources.update_table(info);
   assert!(node.resources.table.specific_node(&id).is_some());
}

#[test]
fn remote_key_value_storage()
{
   let alpha = node::Node::new().unwrap();
   let beta  = node::Node::new().unwrap();

   assert!(alpha.bootstrap_until(beta.local_info(), 1).is_ok());

   let key = hash::SubotaiHash::random();
   let value = hash::SubotaiHash::random();
   let mut receptions =
      beta.receptions()
          .of_kind(receptions::KindFilter::Store)
          .during(time::Duration::seconds(1));

   alpha.resources.store_remotely(beta.id(), key.clone(), value.clone()).unwrap();
   assert!(receptions.next().is_some());

   let retrieved_value = beta.resources.storage.get(&key).unwrap();
   assert_eq!(value, retrieved_value);
}

#[test]
fn node_probing_in_simulated_network()
{
   let mut nodes = simulated_network(40);
   // We manually collect the info tags of all nodes.
   let mut info_nodes: Vec<routing::NodeInfo> = nodes
      .iter()
      .map(|ref node| node.local_info())
      .collect();

   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   let probe_results = head.resources.probe_node(tail.id()).unwrap();

   // We sort our manual collection by distance to the tail node.
   info_nodes.sort_by(|ref info_a, ref info_b| (&info_a.id ^ tail.id()).cmp(&(&info_b.id ^ tail.id())));
   info_nodes.truncate(routing::K_FACTOR); // This guarantees us the closest ids to the tail

   assert_eq!(info_nodes.len(), probe_results.len());
   for (a, b) in probe_results.iter().zip(info_nodes.iter()) {
      assert_eq!(a.id, b.id);
   }
}

#[test]
fn node_probing_in_simulated_unresponsive_network()
{
   let mut nodes = simulated_network(40);
   // We manually collect the info tags of all nodes.
   let mut info_nodes: Vec<routing::NodeInfo> = nodes
      .iter()
      .map(|ref node| node.local_info())
      .collect();

   nodes.drain(10..20);
   let head = nodes.pop_front().unwrap();
   let tail = nodes.pop_back().unwrap();
   let probe_results = head.resources.probe_node(tail.id()).unwrap();

   // We sort our manual collection by distance to the tail node.
   info_nodes.sort_by(|ref info_a, ref info_b| (&info_a.id ^ tail.id()).cmp(&(&info_b.id ^ tail.id())));
   info_nodes.truncate(routing::K_FACTOR); // This guarantees us the closest ids to the tail

   assert_eq!(info_nodes.len(), probe_results.len());
   for (a, b) in probe_results.iter().zip(info_nodes.iter()) {
      assert_eq!(a.id, b.id);
   }
}

fn node_info_no_net(id : hash::SubotaiHash) -> routing::NodeInfo {
   routing::NodeInfo {
      id : id,
      address : net::SocketAddr::from_str("0.0.0.0:0").unwrap(),
   }
}
<|endoftext|>


<commit_before>pub mod ast;
pub mod lexer;
pub mod token;

pub struct Parser {
	pub current: token::Token,
	pub lexer: lexer::Lexer,
	pub peeked: Option<token::Token>,
}

impl Parser {
	pub fn new(input: &str) -> Parser {
		let l = lexer::Lexer::new(input);
		let p = Parser {
			current: token::EOF,
			peeked: None,
			lexer: l
		};
//		p.next_token();
		p
	}

	pub fn parse(&mut self) -> Box<ast::Node> {
		self.expr(1)
	}

	pub fn expr(&mut self, prec: uint) -> Box<ast::Node> {
		let mut lhs = self.atom();
		//println!("expr {}", self.current);
		let mut rhs;
		loop {
			let curr = self.peek_token();
			//println!("{}", curr);
			if token::is_eof(curr) {
				//println!("breaking out of expr loop");
				break;
			}
			let info_tuple = curr.info();
			if info_tuple.is_none() {
				break;
			}
			let (op_prec, op_assoc) = info_tuple.unwrap();
			if op_prec < prec {
				break;
			}
			self.next_token();
			match op_assoc {
				0 => {
					rhs = self.expr(op_prec + 1);
				}
				_  => {
					rhs = self.expr(op_prec)
				}
			}
			lhs = self.op(curr, lhs, rhs);

		}
		//println!("expr ending");
		return lhs;
    	//box ast::Add {
        //	left: box ast::Num { num: 1.0 } as Box<ast::Node>,
        //	right: box ast::Num { num: 2.0 } as Box<ast::Node>,
    	//} as Box<ast::Node>
	}

	pub fn atom(&mut self) -> Box<ast::Node> {

		match self.peek_token() {
			token::LPAREN => {
				//println!("looking for subexpr");
				self.expect('(');
				let e = self.expr(1);
				self.expect(')');
				//println!("found subexpr");
				e
			}
			token::NUMBER(val) => {
				//println!("found number {}", val);
				self.next_token();
				box ast::Num { num: val } as Box<ast::Node>
			}
			a => {
				fail!("unrecognized atom: {}", a);
				box ast::Num { num: 0f64} as Box<ast::Node>
			}
		}
	}

	pub fn op(&self, op: token::Token, lhs: Box<ast::Node>, rhs: Box<ast::Node>)
			-> Box<ast::Node> {
		match op {
			token::ADD => {
				box ast::Add {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::SUB => {
				box ast::Sub {
					left: lhs,
					right: rhs
				} as Box<ast::Node>

			}
			token::MUL => {
				box ast::Mul {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::DIV => {
				box ast::Div {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::CARET => {
				box ast::Pow {
					base: lhs,
					exponent: rhs
				} as Box<ast::Node>
			}
			o => {
				fail!("unrecognized op: {}", o);
				box ast::Num {num: 0f64} as Box<ast::Node>
			}
		}
	}
}

impl Parser {
	pub fn expect(&mut self, tok: char) {
		self.next_token();
		if self.current.to_char() != tok {
			fail!("expected {} but found {}", tok, self.current.to_char());
		}
	}
	pub fn peek_token(&mut self) -> token::Token{
		if self.peeked.is_none() {
			self.peeked = Some(self.lexer.next_token());
		}
		return self.peeked.unwrap();
	}
	pub fn next_token(&mut self) {
		match self.peeked {
			Some(pk) => {
				self.current = pk;
			}
			None => {
				self.current = self.lexer.next_token();
			}
		}
		self.peeked = None;
	}
}
<commit_msg>slightly better parser behavior on empty lines<commit_after>pub mod ast;
pub mod lexer;
pub mod token;

pub struct Parser {
	pub current: token::Token,
	pub lexer: lexer::Lexer,
	pub peeked: Option<token::Token>,
}

impl Parser {
	pub fn new(input: &str) -> Parser {
		let l = lexer::Lexer::new(input);
		let p = Parser {
			current: token::EOF,
			peeked: None,
			lexer: l
		};
//		p.next_token();
		p
	}

	pub fn parse(&mut self) -> Box<ast::Node> {
		self.expr(1)
	}

	pub fn expr(&mut self, prec: uint) -> Box<ast::Node> {
		let mut lhs = self.atom();
		//println!("expr {}", self.current);
		let mut rhs;
		loop {
			let curr = self.peek_token();
			//println!("{}", curr);
			if token::is_eof(curr) {
				//println!("breaking out of expr loop");
				break;
			}
			let info_tuple = curr.info();
			if info_tuple.is_none() {
				break;
			}
			let (op_prec, op_assoc) = info_tuple.unwrap();
			if op_prec < prec {
				break;
			}
			self.next_token();
			match op_assoc {
				0 => {
					rhs = self.expr(op_prec + 1);
				}
				_  => {
					rhs = self.expr(op_prec)
				}
			}
			lhs = self.op(curr, lhs, rhs);

		}
		//println!("expr ending");
		return lhs;
    	//box ast::Add {
        //	left: box ast::Num { num: 1.0 } as Box<ast::Node>,
        //	right: box ast::Num { num: 2.0 } as Box<ast::Node>,
    	//} as Box<ast::Node>
	}

	pub fn atom(&mut self) -> Box<ast::Node> {

		match self.peek_token() {
			token::EOF => {return box ast::Num {num: 0f64} as Box<ast::Node>;}
			token::LPAREN => {
				//println!("looking for subexpr");
				self.expect('(');
				let e = self.expr(1);
				self.expect(')');
				//println!("found subexpr");
				e
			}
			token::NUMBER(val) => {
				//println!("found number {}", val);
				self.next_token();
				box ast::Num { num: val } as Box<ast::Node>
			}
			a => {
				fail!("unrecognized atom: {}", a);
				box ast::Num { num: 0f64} as Box<ast::Node>
			}
		}
	}

	pub fn op(&self, op: token::Token, lhs: Box<ast::Node>, rhs: Box<ast::Node>)
			-> Box<ast::Node> {
		match op {
			token::ADD => {
				box ast::Add {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::SUB => {
				box ast::Sub {
					left: lhs,
					right: rhs
				} as Box<ast::Node>

			}
			token::MUL => {
				box ast::Mul {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::DIV => {
				box ast::Div {
					left: lhs,
					right: rhs
				} as Box<ast::Node>
			}
			token::CARET => {
				box ast::Pow {
					base: lhs,
					exponent: rhs
				} as Box<ast::Node>
			}
			o => {
				fail!("unrecognized op: {}", o);
				box ast::Num {num: 0f64} as Box<ast::Node>
			}
		}
	}
}

impl Parser {
	pub fn expect(&mut self, tok: char) {
		self.next_token();
		if self.current.to_char() != tok {
			fail!("expected {} but found {}", tok, self.current.to_char());
		}
	}
	pub fn peek_token(&mut self) -> token::Token{
		if self.peeked.is_none() {
			self.peeked = Some(self.lexer.next_token());
		}
		return self.peeked.unwrap();
	}
	pub fn next_token(&mut self) {
		match self.peeked {
			Some(pk) => {
				self.current = pk;
			}
			None => {
				self.current = self.lexer.next_token();
			}
		}
		self.peeked = None;
	}
}
<|endoftext|>


<commit_before>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
use std::convert::AsRef;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Get the `PascalStr` as an immutable `&str` reference.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.string.as_str()
    }

    /// Get this string as a `CStr`.
    ///
    /// Returns `Err(InteriorNullError)` if the string contains any interior nulls. If this string is full,
    /// then a new `CString` will be allocated to hold the trailing null byte.
    #[inline]
    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        match self.chars().position(|&c| c == AsciiChar::Null) {
            Some(pos) if pos != (self.len() - 1) => Err(InteriorNullError(pos)),
            _ if self.is_full() && self.string[PASCAL_STRING_BUF_SIZE - 1] != AsciiChar::Null => {
                let str_clone = self.to_owned();
                Ok(Cow::Owned(CString::new(str_clone).unwrap()))
            }
            _ => Ok(Cow::Borrowed(CStr::from_bytes_with_nul(self.as_ref()).unwrap()))
        }
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

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

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..range.end]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        assert!(range.start < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        assert!(range.start < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

#[derive(Clone, Debug, Hash)]
pub struct InteriorNullError(usize);

impl InteriorNullError {
    #[inline]
    pub fn interior_null_index(&self) -> usize {
        self.0
    }
}

impl fmt::Display for InteriorNullError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "interior null at {}", self.0)
    }
}

impl Error for InteriorNullError {
    fn description(&self) -> &str {
        "an interior null was found when creating a CStr from a pascal string"
    }
}
<commit_msg>impl index traits for i32 on PascalStr, so that you can index with an unsuffixed literal<commit_after>use ascii::{AsciiChar, AsciiStr};
use std::ascii::AsciiExt;
use std::borrow::{Cow, ToOwned};
use std::convert::AsRef;
use std::error::Error;
use std::ffi::{CStr, CString};
use std::fmt;
use std::iter::{ExactSizeIterator, Iterator};
use std::ops::{Index, IndexMut, Range, RangeFull, RangeFrom, RangeTo};
use std::slice::{Iter, IterMut};
use ::{PASCAL_STRING_BUF_SIZE, PascalString};

/// A borrowed slice from a `PascalString`. Does not own its data.
#[derive(Eq, Hash, PartialEq, PartialOrd)]
pub struct PascalStr {
    /// The `AsciiStr`, borrowed from the original `PascalString`
    string: AsciiStr
}

impl PascalStr {
    /// Get a pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_ptr(&self) -> *const AsciiChar {
        self.string.as_ptr()
    }

    /// Get a mutable pointer to the first byte of the string buffer.
    #[inline]
    pub fn as_mut_ptr(&mut self) -> *mut AsciiChar {
        self.string.as_mut_ptr()
    }

    /// Get the `PascalStr` as an immutable `&str` reference.
    #[inline]
    pub fn as_str(&self) -> &str {
        self.string.as_str()
    }

    /// Get this string as a `CStr`.
    ///
    /// Returns `Err(InteriorNullError)` if the string contains any interior nulls. If this string is full,
    /// then a new `CString` will be allocated to hold the trailing null byte.
    #[inline]
    pub fn as_cstr(&self) -> Result<Cow<CStr>, InteriorNullError> {
        match self.chars().position(|&c| c == AsciiChar::Null) {
            Some(pos) if pos != (self.len() - 1) => Err(InteriorNullError(pos)),
            _ if self.is_full() && self.string[PASCAL_STRING_BUF_SIZE - 1] != AsciiChar::Null => {
                let str_clone = self.to_owned();
                Ok(Cow::Owned(CString::new(str_clone).unwrap()))
            }
            _ => Ok(Cow::Borrowed(CStr::from_bytes_with_nul(self.as_ref()).unwrap()))
        }
    }

    /// Returns the number of characters used in the string.
    #[inline]
    pub fn len(&self) -> usize {
        self.string.len()
    }

    /// Returns true if the string has a length of 0
    #[inline]
    pub fn is_empty(&self) -> bool {
        self.len() == 0
    }

    /// Returns true if the string has a length of 255.
    ///
    /// When this value is true, no more elements can be pushed onto the string.
    #[inline]
    pub fn is_full(&self) -> bool {
        self.len() == PASCAL_STRING_BUF_SIZE
    }

    /// Get an immutable iterator to the internal character array.
    #[inline]
    pub fn chars<'a>(&'a self) -> Chars<'a> {
        Chars(self.string.as_slice().iter())
    }

    /// Get a mutable iterator to the internal character array.
    #[inline]
    pub fn chars_mut<'a>(&'a mut self) -> CharsMut<'a> {
        CharsMut(self.string.as_mut_slice().iter_mut())
    }
}

impl AsciiExt for PascalStr {
    type Owned = PascalString;

    fn is_ascii(&self) -> bool {
        true
    }

    fn to_ascii_uppercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut upper = PascalString::from(bytes).unwrap();
        upper.make_ascii_uppercase();
        upper
    }

    fn to_ascii_lowercase(&self) -> Self::Owned {
        let bytes: &[u8] = self.as_ref();
        let mut lower = PascalString::from(bytes).unwrap();
        lower.make_ascii_lowercase();
        lower
    }

    fn eq_ignore_ascii_case(&self, other: &Self) -> bool {
        self.string.eq_ignore_ascii_case(&other.string)
    }

    fn make_ascii_uppercase(&mut self) {
        self.string.make_ascii_uppercase()
    }

    fn make_ascii_lowercase(&mut self) {
        self.string.make_ascii_lowercase()
    }
}

impl ToOwned for PascalStr {
    type Owned = PascalString;
    fn to_owned(&self) -> Self::Owned {
        PascalString::from(&self.string).unwrap()
    }
}

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

impl AsRef<[u8]> for PascalStr {
    fn as_ref(&self) -> &[u8] {
        self.string.as_ref()
    }
}

impl AsRef<AsciiStr> for PascalStr {
    fn as_ref(&self) -> &AsciiStr {
        &self.string
    }
}

impl AsMut<AsciiStr> for PascalStr {
    fn as_mut(&mut self) -> &mut AsciiStr {
        &mut self.string
    }
}

impl AsRef<[AsciiChar]> for PascalStr {
    fn as_ref(&self) -> &[AsciiChar] {
        self.string.as_ref()
    }
}

impl AsMut<[AsciiChar]> for PascalStr {
    fn as_mut(&mut self) -> &mut [AsciiChar] {
        self.string.as_mut()
    }
}

impl Index<u8> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: u8) -> &Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<u8> for PascalStr {
    fn index_mut(&mut self, index: u8) -> &mut Self::Output {
        let index = index as usize;
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<usize> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: usize) -> &Self::Output {
        assert!(index < self.len());
        &self.string[index]
    }
}

impl IndexMut<usize> for PascalStr {
    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
        assert!(index < self.len());
        &mut self.string[index]
    }
}

impl Index<i32> for PascalStr {
    type Output = AsciiChar;
    fn index(&self, index: i32) -> &Self::Output {
        assert!(index >= 0);
        assert!((index as usize) < self.len());
        &self.string[index as usize]
    }
}

impl IndexMut<i32> for PascalStr {
    fn index_mut(&mut self, index: i32) -> &mut Self::Output {
        assert!(index >= 0);
        assert!((index as usize) < self.len());
        &mut self.string[index as usize]
    }
}

impl Index<RangeFull> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, _: RangeFull) -> &Self::Output {
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..]
    }
}

impl IndexMut<RangeFull> for PascalStr {
    fn index_mut(&mut self, _: RangeFull) -> &mut Self::Output {
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..]
    }
}

impl Index<Range<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..range.end as usize]
    }
}

impl IndexMut<Range<u8>> for PascalStr {
    fn index_mut(&mut self, range: Range<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..range.end as usize]
    }
}

impl Index<Range<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..range.end]
    }
}

impl IndexMut<Range<usize>> for PascalStr {
    fn index_mut(&mut self, range: Range<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..range.end]
    }
}

impl Index<Range<i32>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: Range<i32>) -> &Self::Output {
        assert!(range.start >= 0);
        assert!((range.start as usize) < self.len());
        assert!(range.end >= 0);
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<Range<i32>> for PascalStr {
    fn index_mut(&mut self, range: Range<i32>) -> &mut Self::Output {
        assert!(range.start >= 0);
        assert!((range.start as usize) < self.len());
        assert!(range.end >= 0);
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<u8>) -> &Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<u8>) -> &mut Self::Output {
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeFrom<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<usize>) -> &Self::Output {
        assert!(range.start < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start..]
    }
}

impl IndexMut<RangeFrom<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<usize>) -> &mut Self::Output {
        assert!(range.start < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start..]
    }
}

impl Index<RangeFrom<i32>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeFrom<i32>) -> &Self::Output {
        assert!(range.start >= 0);
        assert!((range.start as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[range.start as usize..]
    }
}

impl IndexMut<RangeFrom<i32>> for PascalStr {
    fn index_mut(&mut self, range: RangeFrom<i32>) -> &mut Self::Output {
        assert!(range.start >= 0);
        assert!((range.start as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[range.start as usize..]
    }
}

impl Index<RangeTo<u8>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<u8>) -> &Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<u8>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<u8>) -> &mut Self::Output {
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

impl Index<RangeTo<usize>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<usize>) -> &Self::Output {
        assert!(range.end < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end]
    }
}

impl IndexMut<RangeTo<usize>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<usize>) -> &mut Self::Output {
        assert!(range.end < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end]
    }
}

impl Index<RangeTo<i32>> for PascalStr {
    type Output = [AsciiChar];
    fn index(&self, range: RangeTo<i32>) -> &Self::Output {
        assert!(range.end >= 0);
        assert!((range.end as usize) < self.len());
        let char_array: &[AsciiChar] = self.string.as_ref();
        &char_array[..range.end as usize]
    }
}

impl IndexMut<RangeTo<i32>> for PascalStr {
    fn index_mut(&mut self, range: RangeTo<i32>) -> &mut Self::Output {
        assert!(range.end >= 0);
        assert!((range.end as usize) < self.len());
        let char_array: &mut [AsciiChar] = self.string.as_mut();
        &mut char_array[..range.end as usize]
    }
}

/// An immutable iterator over the buffer of a `PascalStr`.
pub struct Chars<'a>(Iter<'a, AsciiChar>);

impl<'a> Iterator for Chars<'a> {
    type Item = &'a AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for Chars<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

/// A mutable iterator over the buffer of a `PascalStr`.
pub struct CharsMut<'a>(IterMut<'a, AsciiChar>);

impl<'a> Iterator for CharsMut<'a> {
    type Item = &'a mut AsciiChar;

    #[inline]
    fn next(&mut self) -> Option<Self::Item> {
        self.0.next()
    }
}

impl<'a> ExactSizeIterator for CharsMut<'a> {
    #[inline]
    fn len(&self) -> usize {
        self.0.len()
    }
}

#[derive(Clone, Debug, Hash)]
pub struct InteriorNullError(usize);

impl InteriorNullError {
    #[inline]
    pub fn interior_null_index(&self) -> usize {
        self.0
    }
}

impl fmt::Display for InteriorNullError {
    fn fmt(&self, fmtr: &mut fmt::Formatter) -> fmt::Result {
        write!(fmtr, "interior null at {}", self.0)
    }
}

impl Error for InteriorNullError {
    fn description(&self) -> &str {
        "an interior null was found when creating a CStr from a pascal string"
    }
}
<|endoftext|>