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

use Api;
use registry::{Enum, Registry, Cmd};
use std::io;

pub mod debug_struct_gen;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write;
}

pub fn gen_struct_name(api: Api) -> &'static str {
    match api {
        Api::Gl  => "Gl",
        Api::Glx => "Glx",
        Api::Wgl => "Wgl",
        Api::Egl => "Egl",
        Api::GlCore => "GlCore",
        Api::Gles1 => "Gles1",
        Api::Gles2 => "Gles2",
    }
}

/// This function generates a `const name: type = value;` item.
pub fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[allow(dead_code, non_upper_case_globals)] pub const {ident}: {types_prefix}{ty} = {value};",
        ident = enm.ident,
        types_prefix = if enm.value == "&'static str" { "" } else { types_prefix },
        ty = enm.ty,
        value = enm.value,
    )
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
/// things that we can't obtain from the XML files.
pub fn gen_types<W>(api: Api, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "{}", include_str!("templates/types/gl.rs")));

    match api {
        Api::Glx => try!(writeln!(dest, "{}", include_str!("templates/types/glx.rs"))),
        Api::Wgl => try!(writeln!(dest, "{}", include_str!("templates/types/wgl.rs"))),
        Api::Egl => try!(writeln!(dest, "{}", include_str!("templates/types/egl.rs"))),
        _ => {},
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // returning
            if with_idents && with_types {
                format!("{}: {}", binding.ident, binding.ty)
            } else if with_types {
                format!("{}", binding.ty)
            } else if with_idents {
                format!("{}", binding.ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(api: Api, cmd: &str) -> String {
    match api {
        Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 => format!("gl{}", cmd),
        Api::Glx => format!("glX{}", cmd),
        Api::Wgl => format!("wgl{}", cmd),
        Api::Egl => format!("egl{}", cmd),
    }
}
<commit_msg>Dont prepend `types::` to `&'static str` types<commit_after>// Copyright 2015 Brendan Zabarauskas and the gl-rs developers
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use Api;
use registry::{Enum, Registry, Cmd};
use std::io;

pub mod debug_struct_gen;
pub mod global_gen;
pub mod static_gen;
pub mod struct_gen;
pub mod static_struct_gen;

/// Trait for a bindings generator.
pub trait Generator {
    /// Builds the GL bindings.
    fn write<W>(&self, registry: &Registry, dest: &mut W) -> io::Result<()> where W: io::Write;
}

pub fn gen_struct_name(api: Api) -> &'static str {
    match api {
        Api::Gl  => "Gl",
        Api::Glx => "Glx",
        Api::Wgl => "Wgl",
        Api::Egl => "Egl",
        Api::GlCore => "GlCore",
        Api::Gles1 => "Gles1",
        Api::Gles2 => "Gles2",
    }
}

/// This function generates a `const name: type = value;` item.
pub fn gen_enum_item<W>(enm: &Enum, types_prefix: &str, dest: &mut W) -> io::Result<()> where W: io::Write {
    writeln!(dest,
        "#[allow(dead_code, non_upper_case_globals)] pub const {ident}: {types_prefix}{ty} = {value};",
        ident = enm.ident,
        types_prefix = if enm.ty == "&'static str" { "" } else { types_prefix },
        ty = enm.ty,
        value = enm.value,
    )
}

/// Generates all the type aliases for a namespace.
///
/// Aliases are either `pub type = ...` or `#[repr(C)] pub struct ... { ... }` and contain all the
/// things that we can't obtain from the XML files.
pub fn gen_types<W>(api: Api, dest: &mut W) -> io::Result<()> where W: io::Write {
    try!(writeln!(dest, "{}", include_str!("templates/types/gl.rs")));

    match api {
        Api::Glx => try!(writeln!(dest, "{}", include_str!("templates/types/glx.rs"))),
        Api::Wgl => try!(writeln!(dest, "{}", include_str!("templates/types/wgl.rs"))),
        Api::Egl => try!(writeln!(dest, "{}", include_str!("templates/types/egl.rs"))),
        _ => {},
    }

    Ok(())
}

/// Generates the list of Rust `Arg`s that a `Cmd` requires.
pub fn gen_parameters(cmd: &Cmd, with_idents: bool, with_types: bool) -> Vec<String> {
    cmd.params.iter()
        .map(|binding| {
            // returning
            if with_idents && with_types {
                format!("{}: {}", binding.ident, binding.ty)
            } else if with_types {
                format!("{}", binding.ty)
            } else if with_idents {
                format!("{}", binding.ident)
            } else {
                panic!()
            }
        })
        .collect()
}

/// Generates the native symbol name of a `Cmd`.
///
/// Example results: `"glClear"`, `"wglCreateContext"`, etc.
pub fn gen_symbol_name(api: Api, cmd: &str) -> String {
    match api {
        Api::Gl | Api::GlCore | Api::Gles1 | Api::Gles2 => format!("gl{}", cmd),
        Api::Glx => format!("glX{}", cmd),
        Api::Wgl => format!("wgl{}", cmd),
        Api::Egl => format!("egl{}", cmd),
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use module::Module;
use storage::file::id::*;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use super::parser::{FileHeaderParser, Parser, ParserError};

use self::header::spec::*;
use self::header::data::*;

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File<'a> {
    owning_module   : &'a Module<'a>,
    header          : FileHeaderData,
    data            : String,
    id              : FileID,
}

impl<'a> File<'a> {

    pub fn new(module: &'a Module<'a>) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object: {:?}", f);
        f
    }

    pub fn from_parser_result(module: &'a Module<'a>, id: FileID, header: FileHeaderData, data: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        f
    }

    pub fn new_with_header(module: &'a Module<'a>, h: FileHeaderData) -> File<'a> {
        let f = File {
            owning_module: module,
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        f
    }

    pub fn new_with_data(module: &'a Module<'a>, d: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        f
    }

    pub fn new_with_content(module: &'a Module<'a>, h: FileHeaderData, d: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: h,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        f
    }

    pub fn header(&self) -> FileHeaderData {
        self.header.clone()
    }

    pub fn data(&self) -> String {
        self.data.clone()
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    pub fn owner(&self) -> &'a Module<'a> {
        self.owning_module
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }
}

impl<'a> Display for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl<'a> Debug for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use super::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::FileHeaderData as FHD;
    use storage::file::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<commit_msg>Add File::edit()<commit_after>use std::error::Error;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

use regex::Regex;

pub mod id;
pub mod id_type;
pub mod header;
pub mod hash;

use module::Module;
use storage::file::id::*;
use storage::file::id_type::FileIDType;
use storage::file::hash::FileHash;
use super::parser::{FileHeaderParser, Parser, ParserError};

use self::header::spec::*;
use self::header::data::*;

/*
 * Internal abstract view on a file. Does not exist on the FS and is just kept
 * internally until it is written to disk.
 */
pub struct File<'a> {
    owning_module   : &'a Module<'a>,
    header          : FileHeaderData,
    data            : String,
    id              : FileID,
}

impl<'a> File<'a> {

    pub fn new(module: &'a Module<'a>) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object: {:?}", f);
        f
    }

    pub fn from_parser_result(module: &'a Module<'a>, id: FileID, header: FileHeaderData, data: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: header,
            data: data,
            id: id,
        };
        debug!("Create new File object from parser result: {:?}", f);
        f
    }

    pub fn new_with_header(module: &'a Module<'a>, h: FileHeaderData) -> File<'a> {
        let f = File {
            owning_module: module,
            header: h,
            data: String::from(""),
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with header: {:?}", f);
        f
    }

    pub fn new_with_data(module: &'a Module<'a>, d: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: FileHeaderData::Null,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with data: {:?}", f);
        f
    }

    pub fn new_with_content(module: &'a Module<'a>, h: FileHeaderData, d: String) -> File<'a> {
        let f = File {
            owning_module: module,
            header: h,
            data: d,
            id: File::get_new_file_id(),
        };
        debug!("Create new File object with content: {:?}", f);
        f
    }

    /**
     * Call editor on the file
     *
     * Return true if exit code from editor was good (and content was changed), false otherwise.
     */
    pub fn edit(rt: &Runtime) {
        unimplemented!()
    }

    pub fn header(&self) -> FileHeaderData {
        self.header.clone()
    }

    pub fn data(&self) -> String {
        self.data.clone()
    }

    pub fn contents(&self) -> (FileHeaderData, String) {
        (self.header(), self.data())
    }

    pub fn id(&self) -> FileID {
        self.id.clone()
    }

    pub fn owner(&self) -> &'a Module<'a> {
        self.owning_module
    }

    pub fn matches_with(&self, r: &Regex) -> bool {
        r.is_match(&self.data[..]) || self.header.matches_with(r)
    }

    fn get_new_file_id() -> FileID {
        use uuid::Uuid;
        let hash = FileHash::from(Uuid::new_v4().to_hyphenated_string());
        FileID::new(FileIDType::UUID, hash)
    }
}

impl<'a> Display for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

impl<'a> Debug for File<'a> {

    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        write!(fmt,
"[File] Owner : '{:?}'
        FileID: '{:?}'
        Header: '{:?}'
        Data  : '{:?}'",
               self.owning_module,
               self.header,
               self.data,
               self.id);
        Ok(())
    }

}

#[cfg(test)]
mod test {
    // we use the JSON parser here, so we can generate FileHeaderData
    use storage::json::parser::JsonHeaderParser;
    use super::match_header_spec;
    use storage::parser::{FileHeaderParser, ParserError};
    use storage::file::FileHeaderData as FHD;
    use storage::file::FileHeaderSpec as FHS;

    #[test]
    fn test_spec_matching() {
        let text = String::from("{\"a\": 1, \"b\": -2}");
        let spec = FHS::Map {
            keys: vec![
                FHS::Key {
                    name: String::from("a"),
                    value_type: Box::new(FHS::UInteger)
                },
                FHS::Key {
                    name: String::from("b"),
                    value_type: Box::new(FHS::Integer)
                }
            ]
        };

        let parser  = JsonHeaderParser::new(Some(spec.clone()));
        let datares = parser.read(Some(text.clone()));
        assert!(datares.is_ok(), "Text could not be parsed: '{}'", text);
        let data = datares.unwrap();

        let matchres = match_header_spec(&spec, &data);
        assert!(matchres.is_none(), "Matching returns error: {:?}", matchres);
    }
}

<|endoftext|>


<commit_before>use num_bigint::BigInt;
use num_bigint::Sign::Plus;
use num_traits::{Bounded, Signed, ToPrimitive, Zero};

use std::cmp::Ordering;
use std::ops::Neg;

mod consts;
use crate::consts::*;

#[macro_use]
mod macros;

#[test]
fn test_scalar_add() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x + y == z);
        assert_signed_scalar_assign_op!(x += y == z);
    }

    for elm in SUM_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&a, &b, &c);
        check(&b, &a, &c);
        check(&c, &na, &b);
        check(&c, &nb, &a);
        check(&a, &nc, &nb);
        check(&b, &nc, &na);
        check(&na, &nb, &nc);
        check(&a, &na, &Zero::zero());
    }
}

#[test]
fn test_scalar_sub() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x - y == z);
        assert_signed_scalar_assign_op!(x -= y == z);
    }

    for elm in SUM_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&c, &a, &b);
        check(&c, &b, &a);
        check(&nb, &a, &nc);
        check(&na, &b, &nc);
        check(&b, &na, &c);
        check(&a, &nb, &c);
        check(&nc, &na, &nb);
        check(&a, &a, &Zero::zero());
    }
}

#[test]
fn test_scalar_mul() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x * y == z);
        assert_signed_scalar_assign_op!(x *= y == z);
    }

    for elm in MUL_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&a, &b, &c);
        check(&b, &a, &c);
        check(&na, &nb, &c);

        check(&na, &b, &nc);
        check(&nb, &a, &nc);
    }
}

#[test]
fn test_scalar_div_rem() {
    fn check_sub(a: &BigInt, b: u32, ans_q: &BigInt, ans_r: &BigInt) {
        let (q, r) = (a / b, a % b);
        if !r.is_zero() {
            assert_eq!(r.sign(), a.sign());
        }
        assert!(r.abs() <= b);
        assert!(*a == b * &q + &r);
        assert!(q == *ans_q);
        assert!(r == *ans_r);

        let b = BigInt::from(b);
        let (a, ans_q, ans_r) = (a.clone(), ans_q.clone(), ans_r.clone());
        assert_signed_scalar_op!(a / b == ans_q);
        assert_signed_scalar_op!(a % b == ans_r);
        assert_signed_scalar_assign_op!(a /= b == ans_q);
        assert_signed_scalar_assign_op!(a %= b == ans_r);

        let nb = -b;
        assert_signed_scalar_op!(a / nb == -ans_q.clone());
        assert_signed_scalar_op!(a % nb == ans_r);
        assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
        assert_signed_scalar_assign_op!(a %= nb == ans_r);
    }

    fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
        check_sub(a, b, q, r);
        check_sub(&a.neg(), b, &q.neg(), &r.neg());
    }

    for elm in MUL_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);

        if a_vec.len() == 1 && a_vec[0] != 0 {
            let a = a_vec[0];
            check(&c, a, &b, &Zero::zero());
        }

        if b_vec.len() == 1 && b_vec[0] != 0 {
            let b = b_vec[0];
            check(&c, b, &a, &Zero::zero());
        }
    }

    for elm in DIV_REM_QUADRUPLES.iter() {
        let (a_vec, b_vec, c_vec, d_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let d = BigInt::from_slice(Plus, d_vec);

        if b_vec.len() == 1 && b_vec[0] != 0 {
            let b = b_vec[0];
            check(&a, b, &c, &d);
        }
    }
}

#[test]
fn test_bigint_scalar_cmp() {
    let m_five = BigInt::from(-5);
    let m_one = BigInt::from(-1);
    let zero = BigInt::from(0);
    let one = BigInt::from(1);
    let five = BigInt::from(5);

    fn cmp_asserts(big: &BigInt, scalar: i32) {
        assert_eq!(big.partial_cmp(&(scalar as i8)), Some(Ordering::Equal));
        assert_eq!((scalar as i8).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as i8 - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as i8 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i8 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i8 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i16)), Some(Ordering::Equal));
        assert_eq!((scalar as i16).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as i16 - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as i16 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i16 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i16 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i32)), Some(Ordering::Equal));
        assert_eq!((scalar as i32).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as i32 - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as i32 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i32 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i32 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i64)), Some(Ordering::Equal));
        assert_eq!((scalar as i64).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as i64 - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as i64 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i64 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i64 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i128)), Some(Ordering::Equal));
        assert_eq!((scalar as i128).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as i128 - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as i128 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i128 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i128 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as isize)), Some(Ordering::Equal));
        assert_eq!((scalar as isize).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(big.partial_cmp(&(scalar as isize - 1)), Some(Ordering::Greater));
        assert_eq!((scalar as isize + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as isize + 1)), Some(Ordering::Less));
        assert_eq!((scalar as isize - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!((scalar as i8), *big);
        assert_eq!(*big, (scalar as i16));
        assert_eq!((scalar as i16), *big);
        assert_eq!(*big, (scalar as i32));
        assert_eq!((scalar as i32), *big);
        assert_eq!(*big, (scalar as i64));
        assert_eq!((scalar as i64), *big);
        assert_eq!(*big, (scalar as i128));
        assert_eq!((scalar as i128), *big);
        assert_eq!(*big, (scalar as isize));
        assert_eq!((scalar as isize), *big);

        if scalar > 0 {
            assert_eq!(*big, (scalar as u8));
            assert_eq!((scalar as u8), *big);
            assert_eq!(*big, (scalar as u16));
            assert_eq!((scalar as u16), *big);
            assert_eq!(*big, (scalar as u32));
            assert_eq!((scalar as u32), *big);
            assert_eq!(*big, (scalar as u64));
            assert_eq!((scalar as u64), *big);
            assert_eq!(*big, (scalar as u128));
            assert_eq!((scalar as u128), *big);
            assert_eq!(*big, (scalar as usize));
            assert_eq!((scalar as usize), *big);
        }
    }

    cmp_asserts(&zero, 0i32);
    cmp_asserts(&one, 1i32);
    cmp_asserts(&five, 5i32);
    cmp_asserts(&m_five, -5i32);
    cmp_asserts(&m_one, -1i32);
}

#[test]
fn test_bigint_scalar_cmp_limits() {
    fn check<T>()
    where
        T: Copy + Bounded,
        BigInt: From<T> + PartialOrd<T>,
    {
        let min = T::min_value();
        let big_min = BigInt::from(min);
        assert_eq!(big_min.partial_cmp(&min), Some(Ordering::Equal));
        assert_eq!((&big_min - 1u32).partial_cmp(&min), Some(Ordering::Less));
        assert_eq!((&big_min + 1u32).partial_cmp(&min), Some(Ordering::Greater));

        let max = T::max_value();
        let big_max = BigInt::from(max);
        assert_eq!(big_max.partial_cmp(&max), Some(Ordering::Equal));
        assert_eq!((&big_max - 1u32).partial_cmp(&max), Some(Ordering::Less));
        assert_eq!((&big_max + 1u32).partial_cmp(&max), Some(Ordering::Greater));
    }

    check::<i8>();
    check::<i16>();
    check::<i32>();
    check::<i64>();
    check::<i128>();
    check::<isize>();

    check::<u8>();
    check::<u16>();
    check::<u32>();
    check::<u64>();
    check::<u128>();
    check::<usize>();
}
<commit_msg>cargo fmt<commit_after>use num_bigint::BigInt;
use num_bigint::Sign::Plus;
use num_traits::{Bounded, Signed, ToPrimitive, Zero};

use std::cmp::Ordering;
use std::ops::Neg;

mod consts;
use crate::consts::*;

#[macro_use]
mod macros;

#[test]
fn test_scalar_add() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x + y == z);
        assert_signed_scalar_assign_op!(x += y == z);
    }

    for elm in SUM_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&a, &b, &c);
        check(&b, &a, &c);
        check(&c, &na, &b);
        check(&c, &nb, &a);
        check(&a, &nc, &nb);
        check(&b, &nc, &na);
        check(&na, &nb, &nc);
        check(&a, &na, &Zero::zero());
    }
}

#[test]
fn test_scalar_sub() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x - y == z);
        assert_signed_scalar_assign_op!(x -= y == z);
    }

    for elm in SUM_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&c, &a, &b);
        check(&c, &b, &a);
        check(&nb, &a, &nc);
        check(&na, &b, &nc);
        check(&b, &na, &c);
        check(&a, &nb, &c);
        check(&nc, &na, &nb);
        check(&a, &a, &Zero::zero());
    }
}

#[test]
fn test_scalar_mul() {
    fn check(x: &BigInt, y: &BigInt, z: &BigInt) {
        let (x, y, z) = (x.clone(), y.clone(), z.clone());
        assert_signed_scalar_op!(x * y == z);
        assert_signed_scalar_assign_op!(x *= y == z);
    }

    for elm in MUL_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let (na, nb, nc) = (-&a, -&b, -&c);

        check(&a, &b, &c);
        check(&b, &a, &c);
        check(&na, &nb, &c);

        check(&na, &b, &nc);
        check(&nb, &a, &nc);
    }
}

#[test]
fn test_scalar_div_rem() {
    fn check_sub(a: &BigInt, b: u32, ans_q: &BigInt, ans_r: &BigInt) {
        let (q, r) = (a / b, a % b);
        if !r.is_zero() {
            assert_eq!(r.sign(), a.sign());
        }
        assert!(r.abs() <= b);
        assert!(*a == b * &q + &r);
        assert!(q == *ans_q);
        assert!(r == *ans_r);

        let b = BigInt::from(b);
        let (a, ans_q, ans_r) = (a.clone(), ans_q.clone(), ans_r.clone());
        assert_signed_scalar_op!(a / b == ans_q);
        assert_signed_scalar_op!(a % b == ans_r);
        assert_signed_scalar_assign_op!(a /= b == ans_q);
        assert_signed_scalar_assign_op!(a %= b == ans_r);

        let nb = -b;
        assert_signed_scalar_op!(a / nb == -ans_q.clone());
        assert_signed_scalar_op!(a % nb == ans_r);
        assert_signed_scalar_assign_op!(a /= nb == -ans_q.clone());
        assert_signed_scalar_assign_op!(a %= nb == ans_r);
    }

    fn check(a: &BigInt, b: u32, q: &BigInt, r: &BigInt) {
        check_sub(a, b, q, r);
        check_sub(&a.neg(), b, &q.neg(), &r.neg());
    }

    for elm in MUL_TRIPLES.iter() {
        let (a_vec, b_vec, c_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let b = BigInt::from_slice(Plus, b_vec);
        let c = BigInt::from_slice(Plus, c_vec);

        if a_vec.len() == 1 && a_vec[0] != 0 {
            let a = a_vec[0];
            check(&c, a, &b, &Zero::zero());
        }

        if b_vec.len() == 1 && b_vec[0] != 0 {
            let b = b_vec[0];
            check(&c, b, &a, &Zero::zero());
        }
    }

    for elm in DIV_REM_QUADRUPLES.iter() {
        let (a_vec, b_vec, c_vec, d_vec) = *elm;
        let a = BigInt::from_slice(Plus, a_vec);
        let c = BigInt::from_slice(Plus, c_vec);
        let d = BigInt::from_slice(Plus, d_vec);

        if b_vec.len() == 1 && b_vec[0] != 0 {
            let b = b_vec[0];
            check(&a, b, &c, &d);
        }
    }
}

#[test]
fn test_bigint_scalar_cmp() {
    let m_five = BigInt::from(-5);
    let m_one = BigInt::from(-1);
    let zero = BigInt::from(0);
    let one = BigInt::from(1);
    let five = BigInt::from(5);

    fn cmp_asserts(big: &BigInt, scalar: i32) {
        assert_eq!(big.partial_cmp(&(scalar as i8)), Some(Ordering::Equal));
        assert_eq!((scalar as i8).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as i8 - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!((scalar as i8 + 1).partial_cmp(big), Some(Ordering::Greater));
        assert_eq!(big.partial_cmp(&(scalar as i8 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i8 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i16)), Some(Ordering::Equal));
        assert_eq!((scalar as i16).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as i16 - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!(
            (scalar as i16 + 1).partial_cmp(big),
            Some(Ordering::Greater)
        );
        assert_eq!(big.partial_cmp(&(scalar as i16 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i16 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i32)), Some(Ordering::Equal));
        assert_eq!((scalar as i32).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as i32 - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!(
            (scalar as i32 + 1).partial_cmp(big),
            Some(Ordering::Greater)
        );
        assert_eq!(big.partial_cmp(&(scalar as i32 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i32 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i64)), Some(Ordering::Equal));
        assert_eq!((scalar as i64).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as i64 - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!(
            (scalar as i64 + 1).partial_cmp(big),
            Some(Ordering::Greater)
        );
        assert_eq!(big.partial_cmp(&(scalar as i64 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i64 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as i128)), Some(Ordering::Equal));
        assert_eq!((scalar as i128).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as i128 - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!(
            (scalar as i128 + 1).partial_cmp(big),
            Some(Ordering::Greater)
        );
        assert_eq!(big.partial_cmp(&(scalar as i128 + 1)), Some(Ordering::Less));
        assert_eq!((scalar as i128 - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!(big.partial_cmp(&(scalar as isize)), Some(Ordering::Equal));
        assert_eq!((scalar as isize).partial_cmp(big), Some(Ordering::Equal));
        assert_eq!(
            big.partial_cmp(&(scalar as isize - 1)),
            Some(Ordering::Greater)
        );
        assert_eq!(
            (scalar as isize + 1).partial_cmp(big),
            Some(Ordering::Greater)
        );
        assert_eq!(
            big.partial_cmp(&(scalar as isize + 1)),
            Some(Ordering::Less)
        );
        assert_eq!((scalar as isize - 1).partial_cmp(big), Some(Ordering::Less));

        assert_eq!((scalar as i8), *big);
        assert_eq!(*big, (scalar as i16));
        assert_eq!((scalar as i16), *big);
        assert_eq!(*big, (scalar as i32));
        assert_eq!((scalar as i32), *big);
        assert_eq!(*big, (scalar as i64));
        assert_eq!((scalar as i64), *big);
        assert_eq!(*big, (scalar as i128));
        assert_eq!((scalar as i128), *big);
        assert_eq!(*big, (scalar as isize));
        assert_eq!((scalar as isize), *big);

        if scalar > 0 {
            assert_eq!(*big, (scalar as u8));
            assert_eq!((scalar as u8), *big);
            assert_eq!(*big, (scalar as u16));
            assert_eq!((scalar as u16), *big);
            assert_eq!(*big, (scalar as u32));
            assert_eq!((scalar as u32), *big);
            assert_eq!(*big, (scalar as u64));
            assert_eq!((scalar as u64), *big);
            assert_eq!(*big, (scalar as u128));
            assert_eq!((scalar as u128), *big);
            assert_eq!(*big, (scalar as usize));
            assert_eq!((scalar as usize), *big);
        }
    }

    cmp_asserts(&zero, 0i32);
    cmp_asserts(&one, 1i32);
    cmp_asserts(&five, 5i32);
    cmp_asserts(&m_five, -5i32);
    cmp_asserts(&m_one, -1i32);
}

#[test]
fn test_bigint_scalar_cmp_limits() {
    fn check<T>()
    where
        T: Copy + Bounded,
        BigInt: From<T> + PartialOrd<T>,
    {
        let min = T::min_value();
        let big_min = BigInt::from(min);
        assert_eq!(big_min.partial_cmp(&min), Some(Ordering::Equal));
        assert_eq!((&big_min - 1u32).partial_cmp(&min), Some(Ordering::Less));
        assert_eq!((&big_min + 1u32).partial_cmp(&min), Some(Ordering::Greater));

        let max = T::max_value();
        let big_max = BigInt::from(max);
        assert_eq!(big_max.partial_cmp(&max), Some(Ordering::Equal));
        assert_eq!((&big_max - 1u32).partial_cmp(&max), Some(Ordering::Less));
        assert_eq!((&big_max + 1u32).partial_cmp(&max), Some(Ordering::Greater));
    }

    check::<i8>();
    check::<i16>();
    check::<i32>();
    check::<i64>();
    check::<i128>();
    check::<isize>();

    check::<u8>();
    check::<u16>();
    check::<u32>();
    check::<u64>();
    check::<u128>();
    check::<usize>();
}
<|endoftext|>


<commit_before>use std::error::Error;

use rustc_serialize::{Decoder, json};

use super::util;

mod error;
pub use self::error::LoadConfigError;

<<<<<<< HEAD
const CONFIG_PATH: &'static str = "./data/config.json";

/// The configuration of the window
=======
>>>>>>> parent of cfa072d... Documented the whole core module, TODO: Document the rest
#[derive(RustcDecodable, RustcEncodable)]
pub struct Config {
  title: String,
  window_size: Vec<u32>
}

impl Config {
  pub fn load() -> Result<Config, LoadConfigError> {
    let config_contents = try!(util::read_utf8_file(CONFIG_PATH));
    // See self::error source for why try! isn't used here.
    match json::decode(&config_contents) {
      Ok(config) => Ok(config),
      Err(e) => Err(LoadConfigError::JsonError(e)),
    }
  }

  pub fn game_title(&self) -> &String {
    &self.title
  }

  pub fn window_size(&self) -> [u32; 2] {
    [ self.window_size[0], self.window_size[1] ]
  }
}
<commit_msg>Fix merge problems<commit_after>use std::error::Error;

use rustc_serialize::{Decoder, json};

use super::util;

mod error;
pub use self::error::LoadConfigError;

const CONFIG_PATH: &'static str = "./data/config.json";

/// The configuration of the window
#[derive(RustcDecodable, RustcEncodable)]
pub struct Config {
  title: String,
  window_size: Vec<u32>
}

impl Config {
  pub fn load() -> Result<Config, LoadConfigError> {
    let config_contents = try!(util::read_utf8_file(CONFIG_PATH));
    // See self::error source for why try! isn't used here.
    match json::decode(&config_contents) {
      Ok(config) => Ok(config),
      Err(e) => Err(LoadConfigError::JsonError(e)),
    }
  }

  pub fn game_title(&self) -> &String {
    &self.title
  }

  pub fn window_size(&self) -> [u32; 2] {
    [ self.window_size[0], self.window_size[1] ]
  }
}
<|endoftext|>


<commit_before>#![cfg(test)]
use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use alloc::AllocBox;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_type::{Binding, JsKey, JsPtrEnum, JsType, JsVar};

pub fn dummy_callback() -> HashSet<Binding> {
    HashSet::new()
}

pub fn make_str(s: &str) -> (JsVar, JsPtrEnum, Binding) {
    let var = JsVar::new(JsType::JsPtr);
    let bnd = var.binding.clone();
    (var, JsPtrEnum::JsStr(JsStrStruct::new(s)), bnd)
}

pub fn make_num(i: f64) -> JsVar {
    JsVar::new(JsType::JsNum(i))
}

pub fn make_obj(kvs: Vec<(JsKey, JsVar)>) -> (JsVar, JsPtrEnum) {
    (JsVar::new(JsType::JsPtr),
     JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs)))
}

pub fn make_alloc_box() -> Rc<RefCell<AllocBox>> {
    Rc::new(RefCell::new(AllocBox::new()))
}

<commit_msg>Remove unused test_utils fn<commit_after>#![cfg(test)]
use std::cell::RefCell;
use std::collections::hash_set::HashSet;
use std::rc::Rc;

use alloc::AllocBox;
use js_types::js_obj::JsObjStruct;
use js_types::js_str::JsStrStruct;
use js_types::js_type::{Binding, JsKey, JsPtrEnum, JsType, JsVar};

pub fn make_str(s: &str) -> (JsVar, JsPtrEnum, Binding) {
    let var = JsVar::new(JsType::JsPtr);
    let bnd = var.binding.clone();
    (var, JsPtrEnum::JsStr(JsStrStruct::new(s)), bnd)
}

pub fn make_num(i: f64) -> JsVar {
    JsVar::new(JsType::JsNum(i))
}

pub fn make_obj(kvs: Vec<(JsKey, JsVar)>) -> (JsVar, JsPtrEnum) {
    (JsVar::new(JsType::JsPtr),
     JsPtrEnum::JsObj(JsObjStruct::new(None, "test", kvs)))
}

pub fn make_alloc_box() -> Rc<RefCell<AllocBox>> {
    Rc::new(RefCell::new(AllocBox::new()))
}

<|endoftext|>


<commit_before>use crate::TokenStream;
use crate::{Ident,Literal};
use crate::{Punct,Spacing};
use crate::Span;

struct CharStream<T: Iterator<Item=char>> {
    inner: ::std::iter::Peekable<T>,
    cur: Option<char>,
}
impl<T: Iterator<Item=char>> CharStream<T> {
    fn new(i: T) -> Self {
        CharStream {
            inner: i.peekable(),
            cur: Some(' '),
            }
    }
    fn consume(&mut self) -> Option<char> {
        self.cur = self.inner.next();
        self.cur
    }
    fn is_complete(&self) -> bool {
        self.cur.is_none()
    }
    fn cur(&self) -> char {
        self.cur.expect("CharStream::cur called with no current")
    }
    fn next(&mut self) -> Option<char> {
        self.inner.peek().cloned()
    }
}

static SYMS: [&[u8]; 53] = [
    b"!" as &[u8],
    b"!=",
    b"#",
    b"$",
    b"%", b"%=",
    b"&", b"&&", b"&=",
    b"(",
    b")",
    b"*", b"*=",
    b"+", b"+=",
    b",",
    b"-", b"-=", b"->",
    b".", b"..", b"...",
    b"/", b"/=",
    b":", b"::",
    b";",
    b"<", b"<-", b"<<", b"<<=", b"<=",
    b"=", b"==", b"=>",
    b">", b">=", b">>", b">>=",
    b"?",
    b"@",
    b"[",
    b"\\",
    b"]",
    b"^", b"^=",
    b"`",
    b"{",
    b"|", b"|=", b"||",
    b"}",
    b"~",
    ];

pub struct LexError {
    inner: &'static str,
}
impl ::std::fmt::Debug for LexError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "LexError({})", self.inner)
    }
}
impl ::std::str::FromStr for TokenStream {
    type Err = LexError;
    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        debug!("TokenStream::from_str({:?})\r", src);
        let mut rv: Vec<crate::TokenTree> = Vec::new();
        let mut it = CharStream::new(src.chars());

        fn err(s: &'static str) -> Result<TokenStream,LexError> {
            Err(LexError { inner: s })
        }

        fn get_ident<T: Iterator<Item=char>>(it: &mut CharStream<T>, mut s: String) -> String
        {
            let mut c = it.cur();
            while c == '_' || c.is_alphanumeric() || c.is_digit(10)
            {
                s.push(c);
                c = some_else!(it.consume() => break);
            }
            s
        }

        'outer: while ! it.is_complete()
        {
            let mut c = it.cur();

            if c.is_whitespace() {
                it.consume();
                continue ;
            }

            if c == '\''
            {
                it.consume();
                c = it.cur();
                if (c.is_alphabetic() || c == '_') && it.next().map(|x| x != '\'').unwrap_or(true) {
                    // Lifetime
                    let ident = get_ident(&mut it, String::new());
                    rv.push(Punct::new('\'', Spacing::Joint).into());
                    rv.push(Ident { is_raw: false, val: ident, span: crate::Span::call_site() }.into());
                }
                else {
                    // Char lit
                    if c == '\\' {
                        panic!("TODO: char literal with escape");
                    }
                    else {
                        rv.push(Literal::character(c).into());
                        match it.consume()
                        {
                        Some('\'') => {},
                        Some(c) => {
                            debug!("Stray charcter '{}'", c);
                            return err("Multiple characters in char literal");
                            },
                        None => {
                            return err("Unterminated char literal");
                            },
                        }
                    }
                }
            }
            else if c == '/' && it.next() == Some('/')
            {
                // Line comment
                while it.consume() != Some('\n') {
                }
            }
            else if c == '/' && it.next() == Some('*')
            {
                // Block comment
                panic!("TODO: Block comment");
            }
            else
            {
                // byte or raw string literals
                if c == 'b' || c == 'r' || c == '"' {
                    let mut c = c;
                    let is_byte = if c == 'b' {
                            c = some_else!(it.consume() => { rv.push(Ident::new("b", crate::Span::call_site()).into()); break });
                            true
                        } else {
                            false
                        };

                    if c == 'r'
                    {
                        // TODO: If this isn't a string, start parsing an ident instead.
                        let ident_str = if is_byte { "br" } else { "r" };
                        c = some_else!(it.consume() => { rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into()); break });
                        let mut hashes = 0;
                        while c == '#' {
                            hashes += 1;
                            c = some_else!(it.consume() => return err("rawstr eof"));
                        }

                        if c != '"' {
                            if hashes == 0 {
                                let s = get_ident(&mut it, ident_str.to_string());
                                rv.push(Ident { is_raw: false, val: s, span: crate::Span::call_site() }.into());
                            }
                            else {
                                rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into());
                            }
                            while hashes > 0 {
                                rv.push(Punct::new('#', if hashes == 1 { Spacing::Alone } else { Spacing::Joint }).into());
                                hashes -= 1;
                            }
                            continue 'outer;
                        }

                        let req_hashes = hashes;
                        let mut rawstr = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("Rawstr eof"));
                            if c == '"' {
                                let mut hashes = 0;
                                while hashes < req_hashes {
                                    c = some_else!(it.consume() => return err("rawstr eof"));
                                    if c != '#' { break ; }
                                    hashes += 1;
                                }

                                if hashes != req_hashes {
                                    rawstr.push('"');
                                    for _ in 0 .. hashes {
                                        rawstr.push('#');
                                    }
                                    rawstr.push(c);
                                }
                                else {
                                    break ;
                                }
                            }
                            else {
                                rawstr.push(c);
                            }
                        }

                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(rawstr.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(rawstr)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else if c == '\''
                    {
                        // Byte character literal?
                        // NOTE: That b'foo is not `b` followed by `'foo`
                        assert!(is_byte);
                        panic!("TODO: Byte character literal");
                    }
                    else if c == '\"'
                    {
                        // String literal
                        let mut s = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("str eof"));
                            if c == '"' {
                                it.consume();
                                break ;
                            }
                            else if c == '\\' {
                                match some_else!(it.consume() => return err("str eof"))
                                {
                                c @ _ => panic!("Unknown escape in string {}", c),
                                }
                            }
                            else {
                                s.push(c);
                            }
                        }
                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(s.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(s)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else
                    {
                        // Could be an ident starting with 'b', or it's just 'b'
                        // - Fall through
                        let ident = get_ident(&mut it, "b".into());
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                        continue 'outer;
                    }
                }

                // Identifier.
                if c.is_alphabetic() || c == '_'
                {
                    let ident = get_ident(&mut it, String::new());
                    if ident == "_" {
                        rv.push(Punct::new('_', Spacing::Alone).into());
                    }
                    else {
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                    }
                }
                else if c.is_digit(10)
                {
                    let base =
                        if c == '0' {
                            match it.consume()
                            {
                            Some('x') => { it.consume(); 16 },
                            Some('o') => { it.consume(); 8 },
                            Some('b') => { it.consume(); 2 },
                            None => {
                                rv.push(Literal::new_u(0, 0).into());
                                continue 'outer;
                                },
                            _ => 10,
                            }
                        }
                        else {
                            10
                        };
                    let mut v = 0;
                    let mut c = it.cur();
                    'int: loop
                    {
                        while c == '_' {
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        if c == 'u' || c == 'i' {
                            let s = get_ident(&mut it, String::new());
                            rv.push(match &*s
                                {
                                "u8"    => Literal::new_u(v,   8), "i8"    => Literal::new_s(v as i128,   8),
                                "u16"   => Literal::new_u(v,  16), "i16"   => Literal::new_s(v as i128,  16),
                                "u32"   => Literal::new_u(v,  32), "i32"   => Literal::new_s(v as i128,  32),
                                "u64"   => Literal::new_u(v,  64), "i64"   => Literal::new_s(v as i128,  64),
                                "u128"  => Literal::new_u(v, 128), "i128"  => Literal::new_s(v as i128, 128),
                                "usize" => Literal::new_u(v,   1), "isize" => Literal::new_s(v as i128,   1),
                                _ => return err("Unexpected integer suffix"),
                                }.into());
                            continue 'outer;
                        }
                        else if let Some(d) = c.to_digit(base) {
                            v *= base as u128;
                            v += d as u128;
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        else if c == '.' {
                            panic!("TODO: Floating point");
                        }
                        else {
                            break;
                        }
                    }
                    rv.push(Literal::new_u(v, 0).into());
                    continue 'outer;
                }
                // Punctuation?
                else if c as u32 <= 0xFF
                {
                    let mut start = match SYMS.iter().position(|v| v[0] == (c as u8))
                        {
                        Some(start) => start,
                        None => {
                            eprint!("Unknown operator character '{}'\r\n", c);
                            return err("Unknown operator")
                            },
                        };
                    let mut end = start+1;
                    while end < SYMS.len() && SYMS[end][0] == c as u8 {
                        end += 1;
                    }

                    let mut ofs = 1;
                    loop
                    {
                        let syms = &SYMS[start..end];
                        assert_eq!(ofs, syms[0].len(), "{:?}", syms[0]);
                        c = some_else!(it.consume() => break);
                        let step = match syms[1..].iter().position(|v| v[ofs] == (c as u8))
                            {
                            Some(s) => s+1,
                            None => break,
                            };
                        start += step;
                        end = start+1;
                        while end < syms.len() && syms[end][ofs] == c as u8 {
                            end += 1;
                        }
                        ofs += 1;
                    }
                    assert_eq!(SYMS[start].len(), ofs);
                    for (i,&c) in Iterator::enumerate(SYMS[start].iter())
                    {
                        let sep = if i == SYMS[start].len() - 1 { Spacing::Alone } else { Spacing::Joint };
                        rv.push(Punct::new(c as char, sep).into());
                    }
                }
                else
                {
                    return err("Unexpected character");
                }
            }
        }

        Ok(TokenStream {
            inner: rv,
            })
    }
}

#[cfg(test)]
mod tests {
    use crate::*;
    use ::std::str::FromStr;

    macro_rules! assert_tt_matches {
        ($have:expr, $exp:expr) => {{
            let e = $exp;
            let h = match $have
                {
                Some(h) => h,
                None => panic!("Unexpected end of stream (expecting {:?})", e),
                };
            assert!( crate::token_tree::tt_eq(&h, &e), "Expected {:?} got {:?}", e, h );
        }};
        ($have:expr) => {{
            match $have
            {
            Some(h) => panic!("Expected end of stream, found {:?}", h),
            None => {},
            }
        }};
    }

    #[test]
    fn lifetime()
    {
        let rv = TokenStream::from_str("foo::bar<'a>").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("foo", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("bar", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('<', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Punct::new('\'', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Ident::new("a", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('>', Spacing::Alone).into());
        assert_tt_matches!(it.next());
    }

    #[test]
    fn trailing_zero()
    {
        let rv = TokenStream::from_str("0").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Literal::new_u(0,0).into());
        assert_tt_matches!(it.next());
    }
    #[test]
    fn tuple_index_method()
    {
        let rv = TokenStream::from_str("key . 1 . def_id").expect("Failed to parse");
        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("key", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Literal::new_u(1,0).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("def_id", Span::call_site()).into());
        assert_tt_matches!(it.next());
    }
}<commit_msg>libproc_macro - Add `Display` impl for `LexError`<commit_after>use crate::TokenStream;
use crate::{Ident,Literal};
use crate::{Punct,Spacing};
use crate::Span;

struct CharStream<T: Iterator<Item=char>> {
    inner: ::std::iter::Peekable<T>,
    cur: Option<char>,
}
impl<T: Iterator<Item=char>> CharStream<T> {
    fn new(i: T) -> Self {
        CharStream {
            inner: i.peekable(),
            cur: Some(' '),
            }
    }
    fn consume(&mut self) -> Option<char> {
        self.cur = self.inner.next();
        self.cur
    }
    fn is_complete(&self) -> bool {
        self.cur.is_none()
    }
    fn cur(&self) -> char {
        self.cur.expect("CharStream::cur called with no current")
    }
    fn next(&mut self) -> Option<char> {
        self.inner.peek().cloned()
    }
}

static SYMS: [&[u8]; 53] = [
    b"!" as &[u8],
    b"!=",
    b"#",
    b"$",
    b"%", b"%=",
    b"&", b"&&", b"&=",
    b"(",
    b")",
    b"*", b"*=",
    b"+", b"+=",
    b",",
    b"-", b"-=", b"->",
    b".", b"..", b"...",
    b"/", b"/=",
    b":", b"::",
    b";",
    b"<", b"<-", b"<<", b"<<=", b"<=",
    b"=", b"==", b"=>",
    b">", b">=", b">>", b">>=",
    b"?",
    b"@",
    b"[",
    b"\\",
    b"]",
    b"^", b"^=",
    b"`",
    b"{",
    b"|", b"|=", b"||",
    b"}",
    b"~",
    ];

pub struct LexError {
    inner: &'static str,
}
impl ::std::fmt::Display for LexError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        f.write_str(self.inner)
    }
}
impl ::std::fmt::Debug for LexError {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "LexError({})", self.inner)
    }
}
impl ::std::str::FromStr for TokenStream {
    type Err = LexError;
    fn from_str(src: &str) -> Result<TokenStream, LexError> {
        debug!("TokenStream::from_str({:?})\r", src);
        let mut rv: Vec<crate::TokenTree> = Vec::new();
        let mut it = CharStream::new(src.chars());

        fn err(s: &'static str) -> Result<TokenStream,LexError> {
            Err(LexError { inner: s })
        }

        fn get_ident<T: Iterator<Item=char>>(it: &mut CharStream<T>, mut s: String) -> String
        {
            let mut c = it.cur();
            while c == '_' || c.is_alphanumeric() || c.is_digit(10)
            {
                s.push(c);
                c = some_else!(it.consume() => break);
            }
            s
        }

        'outer: while ! it.is_complete()
        {
            let mut c = it.cur();

            if c.is_whitespace() {
                it.consume();
                continue ;
            }

            if c == '\''
            {
                it.consume();
                c = it.cur();
                if (c.is_alphabetic() || c == '_') && it.next().map(|x| x != '\'').unwrap_or(true) {
                    // Lifetime
                    let ident = get_ident(&mut it, String::new());
                    rv.push(Punct::new('\'', Spacing::Joint).into());
                    rv.push(Ident { is_raw: false, val: ident, span: crate::Span::call_site() }.into());
                }
                else {
                    // Char lit
                    if c == '\\' {
                        panic!("TODO: char literal with escape");
                    }
                    else {
                        rv.push(Literal::character(c).into());
                        match it.consume()
                        {
                        Some('\'') => {},
                        Some(c) => {
                            debug!("Stray charcter '{}'", c);
                            return err("Multiple characters in char literal");
                            },
                        None => {
                            return err("Unterminated char literal");
                            },
                        }
                    }
                }
            }
            else if c == '/' && it.next() == Some('/')
            {
                // Line comment
                while it.consume() != Some('\n') {
                }
            }
            else if c == '/' && it.next() == Some('*')
            {
                // Block comment
                panic!("TODO: Block comment");
            }
            else
            {
                // byte or raw string literals
                if c == 'b' || c == 'r' || c == '"' {
                    let mut c = c;
                    let is_byte = if c == 'b' {
                            c = some_else!(it.consume() => { rv.push(Ident::new("b", crate::Span::call_site()).into()); break });
                            true
                        } else {
                            false
                        };

                    if c == 'r'
                    {
                        // TODO: If this isn't a string, start parsing an ident instead.
                        let ident_str = if is_byte { "br" } else { "r" };
                        c = some_else!(it.consume() => { rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into()); break });
                        let mut hashes = 0;
                        while c == '#' {
                            hashes += 1;
                            c = some_else!(it.consume() => return err("rawstr eof"));
                        }

                        if c != '"' {
                            if hashes == 0 {
                                let s = get_ident(&mut it, ident_str.to_string());
                                rv.push(Ident { is_raw: false, val: s, span: crate::Span::call_site() }.into());
                            }
                            else {
                                rv.push(Ident::new(ident_str.into(), crate::Span::call_site()).into());
                            }
                            while hashes > 0 {
                                rv.push(Punct::new('#', if hashes == 1 { Spacing::Alone } else { Spacing::Joint }).into());
                                hashes -= 1;
                            }
                            continue 'outer;
                        }

                        let req_hashes = hashes;
                        let mut rawstr = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("Rawstr eof"));
                            if c == '"' {
                                let mut hashes = 0;
                                while hashes < req_hashes {
                                    c = some_else!(it.consume() => return err("rawstr eof"));
                                    if c != '#' { break ; }
                                    hashes += 1;
                                }

                                if hashes != req_hashes {
                                    rawstr.push('"');
                                    for _ in 0 .. hashes {
                                        rawstr.push('#');
                                    }
                                    rawstr.push(c);
                                }
                                else {
                                    break ;
                                }
                            }
                            else {
                                rawstr.push(c);
                            }
                        }

                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(rawstr.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(rawstr)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else if c == '\''
                    {
                        // Byte character literal?
                        // NOTE: That b'foo is not `b` followed by `'foo`
                        assert!(is_byte);
                        panic!("TODO: Byte character literal");
                    }
                    else if c == '\"'
                    {
                        // String literal
                        let mut s = String::new();
                        loop
                        {
                            c = some_else!(it.consume() => return err("str eof"));
                            if c == '"' {
                                it.consume();
                                break ;
                            }
                            else if c == '\\' {
                                match some_else!(it.consume() => return err("str eof"))
                                {
                                c @ _ => panic!("Unknown escape in string {}", c),
                                }
                            }
                            else {
                                s.push(c);
                            }
                        }
                        rv.push(Literal {
                            span: crate::Span::call_site(),
                            val: if is_byte {
                                crate::token_tree::LiteralValue::ByteString(s.into_bytes())
                            } else {
                                crate::token_tree::LiteralValue::String(s)
                            }
                        }.into());
                        continue 'outer;
                    }
                    else
                    {
                        // Could be an ident starting with 'b', or it's just 'b'
                        // - Fall through
                        let ident = get_ident(&mut it, "b".into());
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                        continue 'outer;
                    }
                }

                // Identifier.
                if c.is_alphabetic() || c == '_'
                {
                    let ident = get_ident(&mut it, String::new());
                    if ident == "_" {
                        rv.push(Punct::new('_', Spacing::Alone).into());
                    }
                    else {
                        rv.push(Ident { span: Span::call_site(), is_raw: false, val: ident }.into());
                    }
                }
                else if c.is_digit(10)
                {
                    let base =
                        if c == '0' {
                            match it.consume()
                            {
                            Some('x') => { it.consume(); 16 },
                            Some('o') => { it.consume(); 8 },
                            Some('b') => { it.consume(); 2 },
                            None => {
                                rv.push(Literal::new_u(0, 0).into());
                                continue 'outer;
                                },
                            _ => 10,
                            }
                        }
                        else {
                            10
                        };
                    let mut v = 0;
                    let mut c = it.cur();
                    'int: loop
                    {
                        while c == '_' {
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        if c == 'u' || c == 'i' {
                            let s = get_ident(&mut it, String::new());
                            rv.push(match &*s
                                {
                                "u8"    => Literal::new_u(v,   8), "i8"    => Literal::new_s(v as i128,   8),
                                "u16"   => Literal::new_u(v,  16), "i16"   => Literal::new_s(v as i128,  16),
                                "u32"   => Literal::new_u(v,  32), "i32"   => Literal::new_s(v as i128,  32),
                                "u64"   => Literal::new_u(v,  64), "i64"   => Literal::new_s(v as i128,  64),
                                "u128"  => Literal::new_u(v, 128), "i128"  => Literal::new_s(v as i128, 128),
                                "usize" => Literal::new_u(v,   1), "isize" => Literal::new_s(v as i128,   1),
                                _ => return err("Unexpected integer suffix"),
                                }.into());
                            continue 'outer;
                        }
                        else if let Some(d) = c.to_digit(base) {
                            v *= base as u128;
                            v += d as u128;
                            c = some_else!( it.consume() => { break 'int; } );
                        }
                        else if c == '.' {
                            panic!("TODO: Floating point");
                        }
                        else {
                            break;
                        }
                    }
                    rv.push(Literal::new_u(v, 0).into());
                    continue 'outer;
                }
                // Punctuation?
                else if c as u32 <= 0xFF
                {
                    let mut start = match SYMS.iter().position(|v| v[0] == (c as u8))
                        {
                        Some(start) => start,
                        None => {
                            eprint!("Unknown operator character '{}'\r\n", c);
                            return err("Unknown operator")
                            },
                        };
                    let mut end = start+1;
                    while end < SYMS.len() && SYMS[end][0] == c as u8 {
                        end += 1;
                    }

                    let mut ofs = 1;
                    loop
                    {
                        let syms = &SYMS[start..end];
                        assert_eq!(ofs, syms[0].len(), "{:?}", syms[0]);
                        c = some_else!(it.consume() => break);
                        let step = match syms[1..].iter().position(|v| v[ofs] == (c as u8))
                            {
                            Some(s) => s+1,
                            None => break,
                            };
                        start += step;
                        end = start+1;
                        while end < syms.len() && syms[end][ofs] == c as u8 {
                            end += 1;
                        }
                        ofs += 1;
                    }
                    assert_eq!(SYMS[start].len(), ofs);
                    for (i,&c) in Iterator::enumerate(SYMS[start].iter())
                    {
                        let sep = if i == SYMS[start].len() - 1 { Spacing::Alone } else { Spacing::Joint };
                        rv.push(Punct::new(c as char, sep).into());
                    }
                }
                else
                {
                    return err("Unexpected character");
                }
            }
        }

        Ok(TokenStream {
            inner: rv,
            })
    }
}

#[cfg(test)]
mod tests {
    use crate::*;
    use ::std::str::FromStr;

    macro_rules! assert_tt_matches {
        ($have:expr, $exp:expr) => {{
            let e = $exp;
            let h = match $have
                {
                Some(h) => h,
                None => panic!("Unexpected end of stream (expecting {:?})", e),
                };
            assert!( crate::token_tree::tt_eq(&h, &e), "Expected {:?} got {:?}", e, h );
        }};
        ($have:expr) => {{
            match $have
            {
            Some(h) => panic!("Expected end of stream, found {:?}", h),
            None => {},
            }
        }};
    }

    #[test]
    fn lifetime()
    {
        let rv = TokenStream::from_str("foo::bar<'a>").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("foo", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Punct::new(':', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("bar", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('<', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Punct::new('\'', Spacing::Joint).into());
        assert_tt_matches!(it.next(), Ident::new("a", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('>', Spacing::Alone).into());
        assert_tt_matches!(it.next());
    }

    #[test]
    fn trailing_zero()
    {
        let rv = TokenStream::from_str("0").expect("Failed to parse");

        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Literal::new_u(0,0).into());
        assert_tt_matches!(it.next());
    }
    #[test]
    fn tuple_index_method()
    {
        let rv = TokenStream::from_str("key . 1 . def_id").expect("Failed to parse");
        let mut it = rv.inner.into_iter();
        assert_tt_matches!(it.next(), Ident::new("key", Span::call_site()).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Literal::new_u(1,0).into());
        assert_tt_matches!(it.next(), Punct::new('.', Spacing::Alone).into());
        assert_tt_matches!(it.next(), Ident::new("def_id", Span::call_site()).into());
        assert_tt_matches!(it.next());
    }
}<|endoftext|>