<commit_before>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Result, Source};
use html::HtmlRenderer;
use book::{Book, compile_str};
use token::Token;
use templates::img;
use renderer::Renderer;
use parser::Parser;

use rustc_serialize::base64::{self, ToBase64};

use std::convert::{AsMut, AsRef};

/// Single file HTML renderer
///
/// Renders a standalone, self-contained HTML file
pub struct HtmlSingleRenderer<'a> {
    html: HtmlRenderer<'a>,
}

impl<'a> HtmlSingleRenderer<'a> {
    /// Cretaes a new HtmlSingleRenderer
    pub fn new(book: &'a Book) -> HtmlSingleRenderer<'a> {
        let mut html = HtmlRenderer::new(book);
        html.handler.set_images_mapping(true);
        html.handler.set_base64(true);
        HtmlSingleRenderer {
            html: html,
        }
    }

    /// Renders a token
    ///
    /// Used by render_token implementation of Renderer trait. Separate function
    /// because we need to be able to call it from other renderers.
    ///
    /// See http://lise-henry.github.io/articles/rust_inheritance.html
    #[doc(hidden)]
    pub fn static_render_token<T>(this: &mut T, token: &Token) -> Result<String>
    where T: AsMut<HtmlSingleRenderer<'a>>+AsRef<HtmlSingleRenderer<'a>> +
        AsMut<HtmlRenderer<'a>>+AsRef<HtmlRenderer<'a>> + Renderer
    {
        HtmlRenderer::static_render_token(this, token)
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let menu_svg = img::MENU_SVG.to_base64(base64::STANDARD);
        let menu_svg = format!("data:image/svg+xml;base64,{}", menu_svg);

        let book_svg = img::BOOK_SVG.to_base64(base64::STANDARD);
        let book_svg = format!("data:image/svg+xml;base64,{}", book_svg);

        let pages_svg = img::PAGES_SVG.to_base64(base64::STANDARD);
        let pages_svg = format!("data:image/svg+xml;base64,{}", pages_svg);

        for (i, filename) in self.html.book.filenames.iter().enumerate() {
            self.html.handler.add_link(filename.clone(), format!("#chapter-{}", i));
        }
        let mut content = String::new();

        let mut titles = vec!();
        let mut chapters = vec!();

        for (i, &(n, ref v)) in self.html.book.chapters.iter().enumerate() {
            self.html.chapter_config(i, n, String::new());

            let mut title = String::new();
            for token in v {
                match *token {
                    Token::Header(1, ref vec) => {
                        if self.html.current_hide || self.html.current_numbering == 0 {
                            title = try!(self.html.render_vec(vec));
                        } else {
                            title = try!(self.html.book.get_chapter_header(self.html.current_chapter[0] + 1,
                                                                            try!(self.html.render_vec(vec)),
                                                                            |s| self.render_vec(&try!(Parser::new().parse_inline(s))) ));
                        }
                        break;
                    },
                    _ => {
                        continue;
                    }
                }
            }
            titles.push(title);

            chapters.push(format!(
                "

  {}

",
                i,
                try!(HtmlRenderer::render_html(self, v))));
        }
        self.html.source = Source::empty();

        for (i, chapter) in chapters.iter().enumerate() {
            if self.html.book.options.get_bool("html_single.one_chapter").unwrap()
                && i != 0 {
                content.push_str(&format!(
                    "

  « {}

",
                    i - 1,
                    i,
                    i - 1,
                    titles[i -1]));
            }
            content.push_str(chapter);
            if self.html.book.options.get_bool("html_single.one_chapter").unwrap()
                && i < titles.len() - 1 {
                content.push_str(&format!(
                    "

  {} »

",
                    i + 1,
                    i,
                    i + 1,
                    titles[i + 1]));
            }
        }

        let toc = self.html.toc.render();
        // If display_toc, display the toc inline
        println!("inline_toc: {}",self.html.book.options.get_bool("rendering.inline_toc").unwrap());
        if self.html.book.options.get_bool("rendering.inline_toc").unwrap() {

            content = format!(
                "
{}

{}

{}",
                try!(self.html.get_toc_name()),
                &toc,
                content);
        }

        // Render the CSS
        let template_css = try!(compile_str(try!(self.html.book.get_template("html.css")).as_ref(),
                                            &self.html.book.source,
                                            "could not compile template 'html.css'"));
        let data = try!(self.html.book.get_metadata(|s| self.render_vec(&try!(Parser::new().parse_inline(s)))))
            .insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
            .build();
        let mut res:Vec<u8> = vec!();
        template_css.render_data(&mut res, &data);
        let css = String::from_utf8_lossy(&res);

        // Render the JS
        let template_js = try!(compile_str(try!(self.html.book.get_template("html_single.js")).as_ref(),
                                           &self.html.book.source,
                                           "could not compile template 'html_single.js'"));
        let data = try!(self.html.book.get_metadata(|s| Ok(s.to_owned())))
            .insert_str("book_svg", &book_svg)
            .insert_str("pages_svg", &pages_svg)
            .insert_bool("one_chapter", self.html.book.options.get_bool("html_single.one_chapter").unwrap())
            .insert_str("common_script", self.html.book.get_template("html.js").unwrap().as_ref())
            .build();
        let mut res:Vec<u8> = vec!();
        template_js.render_data(&mut res, &data);
        let js = String::from_utf8_lossy(&res);

        // Render the HTML document
        let mut mapbuilder = try!(self.html.book.get_metadata(|s| self.render_vec(&try!(Parser::new().parse_inline(s)))))
            .insert_str("content", content)
            .insert_str("toc", toc)
            .insert_str("script", js)
            .insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
            .insert_bool("one_chapter", self.html.book.options.get_bool("html_single.one_chapter").unwrap())
            .insert_str("style", css.as_ref())
            .insert_str("print_style", self.html.book.get_template("html.css.print").unwrap())
            .insert_str("menu_svg", menu_svg)
            .insert_str("book_svg", book_svg)
            .insert_str("pages_svg", pages_svg)
            .insert_str("footer", try!(self.html.get_footer()))
            .insert_str("header", try!(self.html.get_header()));
        if self.html.book.options.get_bool("html.highlight_code") == Ok(true) {
            let highlight_js = try!(self.html.book.get_template("html.highlight.js"))
                .as_bytes()
                .to_base64(base64::STANDARD);
            let highlight_js = format!("data:text/javascript;base64,{}", highlight_js);
            mapbuilder = mapbuilder.insert_bool("highlight_code", true)
                .insert_str("highlight_css", try!(self.html.book.get_template("html.highlight.css")))
                .insert_str("highlight_js", highlight_js);
        }
        let data = mapbuilder.build();
        let template = try!(compile_str(try!(self.html.book.get_template("html_single.html")).as_ref(),
                                        &self.html.book.source,
                                        "could not compile template 'html_single.html'"));
        let mut res = vec!();
        template.render_data(&mut res, &data);
        Ok(String::from_utf8_lossy(&res).into_owned())
    }
}

derive_html!{HtmlSingleRenderer<'a>, HtmlSingleRenderer::static_render_token}

<commit_msg>Remove debugging println<commit_after>// Copyright (C) 2016 Élisabeth HENRY.
//
// This file is part of Crowbook.
//
// Crowbook is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published
// by the Free Software Foundation, either version 2.1 of the License, or
// (at your option) any later version.
//
// Caribon is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.
//
// You should have received ba copy of the GNU Lesser General Public License
// along with Crowbook.  If not, see <http://www.gnu.org/licenses/>.

use error::{Result, Source};
use html::HtmlRenderer;
use book::{Book, compile_str};
use token::Token;
use templates::img;
use renderer::Renderer;
use parser::Parser;

use rustc_serialize::base64::{self, ToBase64};

use std::convert::{AsMut, AsRef};

/// Single file HTML renderer
///
/// Renders a standalone, self-contained HTML file
pub struct HtmlSingleRenderer<'a> {
    html: HtmlRenderer<'a>,
}

impl<'a> HtmlSingleRenderer<'a> {
    /// Cretaes a new HtmlSingleRenderer
    pub fn new(book: &'a Book) -> HtmlSingleRenderer<'a> {
        let mut html = HtmlRenderer::new(book);
        html.handler.set_images_mapping(true);
        html.handler.set_base64(true);
        HtmlSingleRenderer {
            html: html,
        }
    }

    /// Renders a token
    ///
    /// Used by render_token implementation of Renderer trait. Separate function
    /// because we need to be able to call it from other renderers.
    ///
    /// See http://lise-henry.github.io/articles/rust_inheritance.html
    #[doc(hidden)]
    pub fn static_render_token<T>(this: &mut T, token: &Token) -> Result<String>
    where T: AsMut<HtmlSingleRenderer<'a>>+AsRef<HtmlSingleRenderer<'a>> +
        AsMut<HtmlRenderer<'a>>+AsRef<HtmlRenderer<'a>> + Renderer
    {
        HtmlRenderer::static_render_token(this, token)
    }

    /// Render books as a standalone HTML file
    pub fn render_book(&mut self) -> Result<String> {
        let menu_svg = img::MENU_SVG.to_base64(base64::STANDARD);
        let menu_svg = format!("data:image/svg+xml;base64,{}", menu_svg);

        let book_svg = img::BOOK_SVG.to_base64(base64::STANDARD);
        let book_svg = format!("data:image/svg+xml;base64,{}", book_svg);

        let pages_svg = img::PAGES_SVG.to_base64(base64::STANDARD);
        let pages_svg = format!("data:image/svg+xml;base64,{}", pages_svg);

        for (i, filename) in self.html.book.filenames.iter().enumerate() {
            self.html.handler.add_link(filename.clone(), format!("#chapter-{}", i));
        }
        let mut content = String::new();

        let mut titles = vec!();
        let mut chapters = vec!();

        for (i, &(n, ref v)) in self.html.book.chapters.iter().enumerate() {
            self.html.chapter_config(i, n, String::new());

            let mut title = String::new();
            for token in v {
                match *token {
                    Token::Header(1, ref vec) => {
                        if self.html.current_hide || self.html.current_numbering == 0 {
                            title = try!(self.html.render_vec(vec));
                        } else {
                            title = try!(self.html.book.get_chapter_header(self.html.current_chapter[0] + 1,
                                                                            try!(self.html.render_vec(vec)),
                                                                            |s| self.render_vec(&try!(Parser::new().parse_inline(s))) ));
                        }
                        break;
                    },
                    _ => {
                        continue;
                    }
                }
            }
            titles.push(title);

            chapters.push(format!(
                "

  {}

",
                i,
                try!(HtmlRenderer::render_html(self, v))));
        }
        self.html.source = Source::empty();

        for (i, chapter) in chapters.iter().enumerate() {
            if self.html.book.options.get_bool("html_single.one_chapter").unwrap()
                && i != 0 {
                content.push_str(&format!(
                    "

  « {}

",
                    i - 1,
                    i,
                    i - 1,
                    titles[i -1]));
            }
            content.push_str(chapter);
            if self.html.book.options.get_bool("html_single.one_chapter").unwrap()
                && i < titles.len() - 1 {
                content.push_str(&format!(
                    "

  {} »

",
                    i + 1,
                    i,
                    i + 1,
                    titles[i + 1]));
            }
        }

        let toc = self.html.toc.render();
        // If display_toc, display the toc inline
        if self.html.book.options.get_bool("rendering.inline_toc").unwrap() {

            content = format!(
                "
{}

{}

{}",
                try!(self.html.get_toc_name()),
                &toc,
                content);
        }

        // Render the CSS
        let template_css = try!(compile_str(try!(self.html.book.get_template("html.css")).as_ref(),
                                            &self.html.book.source,
                                            "could not compile template 'html.css'"));
        let data = try!(self.html.book.get_metadata(|s| self.render_vec(&try!(Parser::new().parse_inline(s)))))
            .insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
            .build();
        let mut res:Vec<u8> = vec!();
        template_css.render_data(&mut res, &data);
        let css = String::from_utf8_lossy(&res);

        // Render the JS
        let template_js = try!(compile_str(try!(self.html.book.get_template("html_single.js")).as_ref(),
                                           &self.html.book.source,
                                           "could not compile template 'html_single.js'"));
        let data = try!(self.html.book.get_metadata(|s| Ok(s.to_owned())))
            .insert_str("book_svg", &book_svg)
            .insert_str("pages_svg", &pages_svg)
            .insert_bool("one_chapter", self.html.book.options.get_bool("html_single.one_chapter").unwrap())
            .insert_str("common_script", self.html.book.get_template("html.js").unwrap().as_ref())
            .build();
        let mut res:Vec<u8> = vec!();
        template_js.render_data(&mut res, &data);
        let js = String::from_utf8_lossy(&res);

        // Render the HTML document
        let mut mapbuilder = try!(self.html.book.get_metadata(|s| self.render_vec(&try!(Parser::new().parse_inline(s)))))
            .insert_str("content", content)
            .insert_str("toc", toc)
            .insert_str("script", js)
            .insert_bool(self.html.book.options.get_str("lang").unwrap(), true)
            .insert_bool("one_chapter", self.html.book.options.get_bool("html_single.one_chapter").unwrap())
            .insert_str("style", css.as_ref())
            .insert_str("print_style", self.html.book.get_template("html.css.print").unwrap())
            .insert_str("menu_svg", menu_svg)
            .insert_str("book_svg", book_svg)
            .insert_str("pages_svg", pages_svg)
            .insert_str("footer", try!(self.html.get_footer()))
            .insert_str("header", try!(self.html.get_header()));
        if self.html.book.options.get_bool("html.highlight_code") == Ok(true) {
            let highlight_js = try!(self.html.book.get_template("html.highlight.js"))
                .as_bytes()
                .to_base64(base64::STANDARD);
            let highlight_js = format!("data:text/javascript;base64,{}", highlight_js);
            mapbuilder = mapbuilder.insert_bool("highlight_code", true)
                .insert_str("highlight_css", try!(self.html.book.get_template("html.highlight.css")))
                .insert_str("highlight_js", highlight_js);
        }
        let data = mapbuilder.build();
        let template = try!(compile_str(try!(self.html.book.get_template("html_single.html")).as_ref(),
                                        &self.html.book.source,
                                        "could not compile template 'html_single.html'"));
        let mut res = vec!();
        template.render_data(&mut res, &data);
        Ok(String::from_utf8_lossy(&res).into_owned())
    }
}

derive_html!{HtmlSingleRenderer<'a>, HtmlSingleRenderer::static_render_token}

<|endoftext|>


<commit_before>
import str::sbuf;
import vec::vbuf;

export program;
export run_program;
export start_program;
export program_output;
export spawn_process;

native "rust" mod rustrt {
    fn rust_run_program(argv: vbuf, in_fd: int, out_fd: int, err_fd: int) ->
       int;
}

fn arg_vec(prog: str, args: vec[str]) -> vec[sbuf] {
    let argptrs = [str::buf(prog)];
    for arg: str  in args { vec::push[sbuf](argptrs, str::buf(arg)); }
    vec::push[sbuf](argptrs, 0 as sbuf);
    ret argptrs;
}

fn spawn_process(prog: str, args: vec[str], in_fd: int, out_fd: int,
                 err_fd: int) -> int {
    // Note: we have to hold on to this vector reference while we hold a
    // pointer to its buffer
    let argv = arg_vec(prog, args);
    let pid = rustrt::rust_run_program(vec::buf(argv), in_fd, out_fd, err_fd);
    ret pid;
}

fn run_program(prog: str, args: vec[str]) -> int {
    ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
}

type program =
    obj {
        fn get_id() -> int ;
        fn input() -> io::writer ;
        fn output() -> io::reader ;
        fn close_input() ;
        fn finish() -> int ;
    };

fn start_program(prog: str, args: vec[str]) -> @program {
    let pipe_input = os::pipe();
    let pipe_output = os::pipe();
    let pid = spawn_process(prog, args, pipe_input.in, pipe_output.out, 0);

    if pid == -1 { fail; }
    os::libc::close(pipe_input.in);
    os::libc::close(pipe_output.out);
    obj new_program(pid: int,
                    mutable in_fd: int,
                    out_file: os::libc::FILE,
                    mutable finished: bool) {
        fn get_id() -> int { ret pid; }
        fn input() -> io::writer {
            ret io::new_writer(io::fd_buf_writer(in_fd, false));
        }
        fn output() -> io::reader {
            ret io::new_reader(io::FILE_buf_reader(out_file, false));
        }
        fn close_input() {
            let invalid_fd = -1;
            if in_fd != invalid_fd {
                os::libc::close(in_fd);
                in_fd = invalid_fd;
            }
        }
        fn finish() -> int {
            if finished { ret 0; }
            finished = true;
            self.close_input();
            ret os::waitpid(pid);
        }
        drop {
            self.close_input();
            if !finished { os::waitpid(pid); }
            os::libc::fclose(out_file);
        }
    }
    ret @new_program(pid, pipe_input.out, os::fd_FILE(pipe_output.in), false);
}

fn program_output(prog: str, args: vec[str]) -> {status: int, out: str} {
    let pr = start_program(prog, args);
    pr.close_input();
    let out = pr.output();
    let buf = "";
    while !out.eof() {
        let bytes = out.read_bytes(4096u);
        buf += str::unsafe_from_bytes(bytes);
    }
    ret {status: pr.finish(), out: buf};
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<commit_msg>Make program_output also return stderr<commit_after>
import str::sbuf;
import vec::vbuf;

export program;
export run_program;
export start_program;
export program_output;
export spawn_process;

native "rust" mod rustrt {
    fn rust_run_program(argv: vbuf, in_fd: int, out_fd: int, err_fd: int) ->
       int;
}

fn arg_vec(prog: str, args: vec[str]) -> vec[sbuf] {
    let argptrs = [str::buf(prog)];
    for arg: str  in args { vec::push[sbuf](argptrs, str::buf(arg)); }
    vec::push[sbuf](argptrs, 0 as sbuf);
    ret argptrs;
}

fn spawn_process(prog: str, args: vec[str], in_fd: int, out_fd: int,
                 err_fd: int) -> int {
    // Note: we have to hold on to this vector reference while we hold a
    // pointer to its buffer
    let argv = arg_vec(prog, args);
    let pid = rustrt::rust_run_program(vec::buf(argv), in_fd, out_fd, err_fd);
    ret pid;
}

fn run_program(prog: str, args: vec[str]) -> int {
    ret os::waitpid(spawn_process(prog, args, 0, 0, 0));
}

type program =
    obj {
        fn get_id() -> int ;
        fn input() -> io::writer ;
        fn output() -> io::reader ;
        fn err() -> io::reader ;
        fn close_input() ;
        fn finish() -> int ;
    };

fn start_program(prog: str, args: vec[str]) -> @program {
    let pipe_input = os::pipe();
    let pipe_output = os::pipe();
    let pipe_err = os::pipe();
    let pid = spawn_process(prog, args, pipe_input.in, pipe_output.out,
                            pipe_err.out);

    if pid == -1 { fail; }
    os::libc::close(pipe_input.in);
    os::libc::close(pipe_output.out);
    os::libc::close(pipe_err.out);
    obj new_program(pid: int,
                    mutable in_fd: int,
                    out_file: os::libc::FILE,
                    err_file: os::libc::FILE,
                    mutable finished: bool) {
        fn get_id() -> int { ret pid; }
        fn input() -> io::writer {
            ret io::new_writer(io::fd_buf_writer(in_fd, false));
        }
        fn output() -> io::reader {
            ret io::new_reader(io::FILE_buf_reader(out_file, false));
        }
        fn err() -> io::reader {
            ret io::new_reader(io::FILE_buf_reader(err_file, false));
        }
        fn close_input() {
            let invalid_fd = -1;
            if in_fd != invalid_fd {
                os::libc::close(in_fd);
                in_fd = invalid_fd;
            }
        }
        fn finish() -> int {
            if finished { ret 0; }
            finished = true;
            self.close_input();
            ret os::waitpid(pid);
        }
        drop {
            self.close_input();
            if !finished { os::waitpid(pid); }
            os::libc::fclose(out_file);
            os::libc::fclose(err_file);
        }
    }
    ret @new_program(pid,
                     pipe_input.out,
                     os::fd_FILE(pipe_output.in),
                     os::fd_FILE(pipe_err.in),
                     false);
}

fn read_all(rd: &io::reader) -> str {
    let buf = "";
    while !rd.eof() {
        let bytes = rd.read_bytes(4096u);
        buf += str::unsafe_from_bytes(bytes);
    }
    ret buf;
}

fn program_output(prog: str, args: vec[str])
    -> {status: int, out: str, err: str} {
    let pr = start_program(prog, args);
    pr.close_input();
    ret {status: pr.finish(),
         out: read_all(pr.output()),
         err: read_all(pr.err())};
}
// Local Variables:
// mode: rust
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// compile-command: "make -k -C $RBUILD 2>&1 | sed -e 's/\\/x\\//x:\\//g'";
// End:
<|endoftext|>


<commit_before>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Integer and floating-point number formatting

// FIXME: #6220 Implement floating point formatting

#![allow(unsigned_negation)]

use fmt;
use iter::IteratorExt;
use num::{Int, cast};
use slice::SliceExt;
use str;

/// A type that represents a specific radix
#[doc(hidden)]
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str { "" }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 64
        // characters for a base 2 number.
        let zero = Int::zero();
        let is_positive = x >= zero;
        let mut buf = [0u8; 64];
        let mut curr = buf.len();
        let base = cast(self.base()).unwrap();
        if is_positive {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.iter_mut().rev() {
                let n = x % base;                         // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero { break };                   // No more digits left to accumulate.
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.iter_mut().rev() {
                let n = zero - (x % base);                // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero { break };                   // No more digits left to accumulate.
            }
        }
        let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
        f.pad_integral(is_positive, self.prefix(), buf)
    }
}

/// A binary (base 2) radix
#[derive(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[derive(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[derive(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[derive(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[derive(Clone, PartialEq)]
pub struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix! { Binary,    2, "0b", x @  0 ...  2 => b'0' + x }
radix! { Octal,     8, "0o", x @  0 ...  7 => b'0' + x }
radix! { Decimal,  10, "",   x @  0 ...  9 => b'0' + x }
radix! { LowerHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'a' + (x - 10) }
radix! { UpperHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'A' + (x - 10) }

/// A radix with in the range of `2..36`.
#[derive(Clone, Copy, PartialEq)]
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
pub struct Radix {
    base: u8,
}

impl Radix {
    fn new(base: u8) -> Radix {
        assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base);
        Radix { base: base }
    }
}

impl GenericRadix for Radix {
    fn base(&self) -> u8 { self.base }
    fn digit(&self, x: u8) -> u8 {
        match x {
            x @  0 ... 9 => b'0' + x,
            x if x < self.base() => b'a' + (x - 10),
            x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
        }
    }
}

/// A helper type for formatting radixes.
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
#[derive(Copy)]
pub struct RadixFmt<T, R>(T, R);

/// Constructs a radix formatter in the range of `2..36`.
///
/// # Example
///
/// ```
/// use std::fmt::radix;
/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string());
/// ```
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
    RadixFmt(x, Radix::new(base))
}

macro_rules! radix_fmt {
    ($T:ty as $U:ty, $fmt:ident, $S:expr) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Display for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
            }
        }
    }
}
macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}

macro_rules! show {
    ($T:ident with $S:expr) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
    }
}
macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        integer! { $Int, $Uint, stringify!($Int), stringify!($Uint) }
    };
    ($Int:ident, $Uint:ident, $SI:expr, $SU:expr) => {
        int_base! { Display  for $Int as $Int   -> Decimal }
        int_base! { Binary   for $Int as $Uint  -> Binary }
        int_base! { Octal    for $Int as $Uint  -> Octal }
        int_base! { LowerHex for $Int as $Uint  -> LowerHex }
        int_base! { UpperHex for $Int as $Uint  -> UpperHex }
        radix_fmt! { $Int as $Int, fmt_int, $SI }
        show! { $Int with $SI }

        int_base! { Display  for $Uint as $Uint -> Decimal }
        int_base! { Binary   for $Uint as $Uint -> Binary }
        int_base! { Octal    for $Uint as $Uint -> Octal }
        int_base! { LowerHex for $Uint as $Uint -> LowerHex }
        int_base! { UpperHex for $Uint as $Uint -> UpperHex }
        radix_fmt! { $Uint as $Uint, fmt_int, $SU }
        show! { $Uint with $SU }
    }
}
integer! { isize, usize, "i", "u" }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
<commit_msg>Rollup merge of #22916 - rprichard:fmt-num-cleanup, r=alexcrichton<commit_after>// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Integer and floating-point number formatting

// FIXME: #6220 Implement floating point formatting

#![allow(unsigned_negation)]

use fmt;
use iter::IteratorExt;
use num::{Int, cast};
use slice::SliceExt;
use str;

/// A type that represents a specific radix
#[doc(hidden)]
trait GenericRadix {
    /// The number of digits.
    fn base(&self) -> u8;

    /// A radix-specific prefix string.
    fn prefix(&self) -> &'static str { "" }

    /// Converts an integer to corresponding radix digit.
    fn digit(&self, x: u8) -> u8;

    /// Format an integer using the radix using a formatter.
    fn fmt_int<T: Int>(&self, mut x: T, f: &mut fmt::Formatter) -> fmt::Result {
        // The radix can be as low as 2, so we need a buffer of at least 64
        // characters for a base 2 number.
        let zero = Int::zero();
        let is_positive = x >= zero;
        let mut buf = [0u8; 64];
        let mut curr = buf.len();
        let base = cast(self.base()).unwrap();
        if is_positive {
            // Accumulate each digit of the number from the least significant
            // to the most significant figure.
            for byte in buf.iter_mut().rev() {
                let n = x % base;                         // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero { break };                   // No more digits left to accumulate.
            }
        } else {
            // Do the same as above, but accounting for two's complement.
            for byte in buf.iter_mut().rev() {
                let n = zero - (x % base);                // Get the current place value.
                x = x / base;                             // Deaccumulate the number.
                *byte = self.digit(cast(n).unwrap());     // Store the digit in the buffer.
                curr -= 1;
                if x == zero { break };                   // No more digits left to accumulate.
            }
        }
        let buf = unsafe { str::from_utf8_unchecked(&buf[curr..]) };
        f.pad_integral(is_positive, self.prefix(), buf)
    }
}

/// A binary (base 2) radix
#[derive(Clone, PartialEq)]
struct Binary;

/// An octal (base 8) radix
#[derive(Clone, PartialEq)]
struct Octal;

/// A decimal (base 10) radix
#[derive(Clone, PartialEq)]
struct Decimal;

/// A hexadecimal (base 16) radix, formatted with lower-case characters
#[derive(Clone, PartialEq)]
struct LowerHex;

/// A hexadecimal (base 16) radix, formatted with upper-case characters
#[derive(Clone, PartialEq)]
struct UpperHex;

macro_rules! radix {
    ($T:ident, $base:expr, $prefix:expr, $($x:pat => $conv:expr),+) => {
        impl GenericRadix for $T {
            fn base(&self) -> u8 { $base }
            fn prefix(&self) -> &'static str { $prefix }
            fn digit(&self, x: u8) -> u8 {
                match x {
                    $($x => $conv,)+
                    x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
                }
            }
        }
    }
}

radix! { Binary,    2, "0b", x @  0 ...  2 => b'0' + x }
radix! { Octal,     8, "0o", x @  0 ...  7 => b'0' + x }
radix! { Decimal,  10, "",   x @  0 ...  9 => b'0' + x }
radix! { LowerHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'a' + (x - 10) }
radix! { UpperHex, 16, "0x", x @  0 ...  9 => b'0' + x,
                             x @ 10 ... 15 => b'A' + (x - 10) }

/// A radix with in the range of `2..36`.
#[derive(Clone, Copy, PartialEq)]
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
pub struct Radix {
    base: u8,
}

impl Radix {
    fn new(base: u8) -> Radix {
        assert!(2 <= base && base <= 36, "the base must be in the range of 2..36: {}", base);
        Radix { base: base }
    }
}

impl GenericRadix for Radix {
    fn base(&self) -> u8 { self.base }
    fn digit(&self, x: u8) -> u8 {
        match x {
            x @  0 ... 9 => b'0' + x,
            x if x < self.base() => b'a' + (x - 10),
            x => panic!("number not in the range 0..{}: {}", self.base() - 1, x),
        }
    }
}

/// A helper type for formatting radixes.
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
#[derive(Copy)]
pub struct RadixFmt<T, R>(T, R);

/// Constructs a radix formatter in the range of `2..36`.
///
/// # Example
///
/// ```
/// use std::fmt::radix;
/// assert_eq!(format!("{}", radix(55, 36)), "1j".to_string());
/// ```
#[unstable(feature = "core",
           reason = "may be renamed or move to a different module")]
pub fn radix<T>(x: T, base: u8) -> RadixFmt<T, Radix> {
    RadixFmt(x, Radix::new(base))
}

macro_rules! radix_fmt {
    ($T:ty as $U:ty, $fmt:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Display for RadixFmt<$T, Radix> {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                match *self { RadixFmt(ref x, radix) => radix.$fmt(*x as $U, f) }
            }
        }
    }
}
macro_rules! int_base {
    ($Trait:ident for $T:ident as $U:ident -> $Radix:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::$Trait for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                $Radix.fmt_int(*self as $U, f)
            }
        }
    }
}

macro_rules! debug {
    ($T:ident) => {
        #[stable(feature = "rust1", since = "1.0.0")]
        impl fmt::Debug for $T {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                fmt::Display::fmt(self, f)
            }
        }
    }
}
macro_rules! integer {
    ($Int:ident, $Uint:ident) => {
        int_base! { Display  for $Int as $Int   -> Decimal }
        int_base! { Binary   for $Int as $Uint  -> Binary }
        int_base! { Octal    for $Int as $Uint  -> Octal }
        int_base! { LowerHex for $Int as $Uint  -> LowerHex }
        int_base! { UpperHex for $Int as $Uint  -> UpperHex }
        radix_fmt! { $Int as $Int, fmt_int }
        debug! { $Int }

        int_base! { Display  for $Uint as $Uint -> Decimal }
        int_base! { Binary   for $Uint as $Uint -> Binary }
        int_base! { Octal    for $Uint as $Uint -> Octal }
        int_base! { LowerHex for $Uint as $Uint -> LowerHex }
        int_base! { UpperHex for $Uint as $Uint -> UpperHex }
        radix_fmt! { $Uint as $Uint, fmt_int }
        debug! { $Uint }
    }
}
integer! { isize, usize }
integer! { i8, u8 }
integer! { i16, u16 }
integer! { i32, u32 }
integer! { i64, u64 }
<|endoftext|>


<commit_before>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cmp;
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;

// =============================================================================
// Forwarding implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, R: Read + ?Sized> Read for &'a mut R {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        (**self).initializer()
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        (**self).read_exact(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, W: Write + ?Sized> Write for &'a mut W {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read + ?Sized> Read for Box<R> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        (**self).initializer()
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        (**self).read_exact(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + ?Sized> Write for Box<W> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S: Seek + ?Sized> Seek for Box<S> {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

// =============================================================================
// In-memory buffer implementations

/// Read is implemented for `&[u8]` by copying from the slice.
///
/// Note that reading updates the slice to point to the yet unread part.
/// The slice will be empty when EOF is reached.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Read for &'a [u8] {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let amt = cmp::min(buf.len(), self.len());
        let (a, b) = self.split_at(amt);

        // First check if the amount of bytes we want to read is small:
        // `copy_from_slice` will generally expand to a call to `memcpy`, and
        // for a single byte the overhead is significant.
        if amt == 1 {
            buf[0] = a[0];
        } else {
            buf[..amt].copy_from_slice(a);
        }

        *self = b;
        Ok(amt)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        if buf.len() > self.len() {
            return Err(Error::new(ErrorKind::UnexpectedEof,
                                  "failed to fill whole buffer"));
        }
        let (a, b) = self.split_at(buf.len());

        // First check if the amount of bytes we want to read is small:
        // `copy_from_slice` will generally expand to a call to `memcpy`, and
        // for a single byte the overhead is significant.
        if buf.len() == 1 {
            buf[0] = a[0];
        } else {
            buf.copy_from_slice(a);
        }

        *self = b;
        Ok(())
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for &'a [u8] {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }

    #[inline]
    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}

/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
/// its data.
///
/// Note that writing updates the slice to point to the yet unwritten part.
/// The slice will be empty when it has been completely overwritten.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for &'a mut [u8] {
    #[inline]
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = cmp::min(data.len(), self.len());
        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
        a.copy_from_slice(&data[..amt]);
        *self = b;
        Ok(amt)
    }

    #[inline]
    fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
        if self.write(data)? == data.len() {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
        }
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

/// Write is implemented for `Vec<u8>` by appending to the vector.
/// The vector will grow as needed.
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Vec<u8> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(buf);
        Ok(buf.len())
    }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.extend_from_slice(buf);
        Ok(())
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use test;

    #[bench]
    fn bench_read_slice(b: &mut test::Bencher) {
        let buf = [5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in 0..8 {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_slice(b: &mut test::Bencher) {
        let mut buf = [0; 1024];
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in 0..8 {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }

    #[bench]
    fn bench_read_vec(b: &mut test::Bencher) {
        let buf = vec![5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in 0..8 {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_vec(b: &mut test::Bencher) {
        let mut buf = Vec::with_capacity(1024);
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in 0..8 {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }
}
<commit_msg>Add read_to_end implementation to &[u8]'s Read impl<commit_after>// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use cmp;
use io::{self, SeekFrom, Read, Initializer, Write, Seek, BufRead, Error, ErrorKind};
use fmt;
use mem;

// =============================================================================
// Forwarding implementations

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, R: Read + ?Sized> Read for &'a mut R {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        (**self).initializer()
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        (**self).read_exact(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, W: Write + ?Sized> Write for &'a mut W {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, S: Seek + ?Sized> Seek for &'a mut S {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a, B: BufRead + ?Sized> BufRead for &'a mut B {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<R: Read + ?Sized> Read for Box<R> {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        (**self).read(buf)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        (**self).initializer()
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_to_end(buf)
    }

    #[inline]
    fn read_to_string(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_to_string(buf)
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        (**self).read_exact(buf)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<W: Write + ?Sized> Write for Box<W> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> { (**self).write(buf) }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { (**self).flush() }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        (**self).write_all(buf)
    }

    #[inline]
    fn write_fmt(&mut self, fmt: fmt::Arguments) -> io::Result<()> {
        (**self).write_fmt(fmt)
    }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<S: Seek + ?Sized> Seek for Box<S> {
    #[inline]
    fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> { (**self).seek(pos) }
}
#[stable(feature = "rust1", since = "1.0.0")]
impl<B: BufRead + ?Sized> BufRead for Box<B> {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { (**self).fill_buf() }

    #[inline]
    fn consume(&mut self, amt: usize) { (**self).consume(amt) }

    #[inline]
    fn read_until(&mut self, byte: u8, buf: &mut Vec<u8>) -> io::Result<usize> {
        (**self).read_until(byte, buf)
    }

    #[inline]
    fn read_line(&mut self, buf: &mut String) -> io::Result<usize> {
        (**self).read_line(buf)
    }
}

// =============================================================================
// In-memory buffer implementations

/// Read is implemented for `&[u8]` by copying from the slice.
///
/// Note that reading updates the slice to point to the yet unread part.
/// The slice will be empty when EOF is reached.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Read for &'a [u8] {
    #[inline]
    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
        let amt = cmp::min(buf.len(), self.len());
        let (a, b) = self.split_at(amt);

        // First check if the amount of bytes we want to read is small:
        // `copy_from_slice` will generally expand to a call to `memcpy`, and
        // for a single byte the overhead is significant.
        if amt == 1 {
            buf[0] = a[0];
        } else {
            buf[..amt].copy_from_slice(a);
        }

        *self = b;
        Ok(amt)
    }

    #[inline]
    unsafe fn initializer(&self) -> Initializer {
        Initializer::nop()
    }

    #[inline]
    fn read_exact(&mut self, buf: &mut [u8]) -> io::Result<()> {
        if buf.len() > self.len() {
            return Err(Error::new(ErrorKind::UnexpectedEof,
                                  "failed to fill whole buffer"));
        }
        let (a, b) = self.split_at(buf.len());

        // First check if the amount of bytes we want to read is small:
        // `copy_from_slice` will generally expand to a call to `memcpy`, and
        // for a single byte the overhead is significant.
        if buf.len() == 1 {
            buf[0] = a[0];
        } else {
            buf.copy_from_slice(a);
        }

        *self = b;
        Ok(())
    }

    #[inline]
    fn read_to_end(&mut self, buf: &mut Vec<u8>) -> io::Result<usize> {
        buf.extend_from_slice(*self);
        let len = self.len();
        *self = &self[len..];
        Ok(len)
    }
}

#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> BufRead for &'a [u8] {
    #[inline]
    fn fill_buf(&mut self) -> io::Result<&[u8]> { Ok(*self) }

    #[inline]
    fn consume(&mut self, amt: usize) { *self = &self[amt..]; }
}

/// Write is implemented for `&mut [u8]` by copying into the slice, overwriting
/// its data.
///
/// Note that writing updates the slice to point to the yet unwritten part.
/// The slice will be empty when it has been completely overwritten.
#[stable(feature = "rust1", since = "1.0.0")]
impl<'a> Write for &'a mut [u8] {
    #[inline]
    fn write(&mut self, data: &[u8]) -> io::Result<usize> {
        let amt = cmp::min(data.len(), self.len());
        let (a, b) = mem::replace(self, &mut []).split_at_mut(amt);
        a.copy_from_slice(&data[..amt]);
        *self = b;
        Ok(amt)
    }

    #[inline]
    fn write_all(&mut self, data: &[u8]) -> io::Result<()> {
        if self.write(data)? == data.len() {
            Ok(())
        } else {
            Err(Error::new(ErrorKind::WriteZero, "failed to write whole buffer"))
        }
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

/// Write is implemented for `Vec<u8>` by appending to the vector.
/// The vector will grow as needed.
#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Vec<u8> {
    #[inline]
    fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
        self.extend_from_slice(buf);
        Ok(buf.len())
    }

    #[inline]
    fn write_all(&mut self, buf: &[u8]) -> io::Result<()> {
        self.extend_from_slice(buf);
        Ok(())
    }

    #[inline]
    fn flush(&mut self) -> io::Result<()> { Ok(()) }
}

#[cfg(test)]
mod tests {
    use io::prelude::*;
    use test;

    #[bench]
    fn bench_read_slice(b: &mut test::Bencher) {
        let buf = [5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in 0..8 {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_slice(b: &mut test::Bencher) {
        let mut buf = [0; 1024];
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in 0..8 {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }

    #[bench]
    fn bench_read_vec(b: &mut test::Bencher) {
        let buf = vec![5; 1024];
        let mut dst = [0; 128];

        b.iter(|| {
            let mut rd = &buf[..];
            for _ in 0..8 {
                let _ = rd.read(&mut dst);
                test::black_box(&dst);
            }
        })
    }

    #[bench]
    fn bench_write_vec(b: &mut test::Bencher) {
        let mut buf = Vec::with_capacity(1024);
        let src = [5; 128];

        b.iter(|| {
            let mut wr = &mut buf[..];
            for _ in 0..8 {
                let _ = wr.write_all(&src);
                test::black_box(&wr);
            }
        })
    }
}
<|endoftext|>


<commit_before>#[doc = "The main parser interface"];
import dvec::extensions;

export parse_sess;
export next_node_id;
export new_parser_from_file;
export new_parser_from_source_str;
export parse_crate_from_file;
export parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str;
export parse_item_from_source_str;
export parse_from_source_str;

import parser::parser;
import attr::parser_attr;
import common::parser_common;
import ast::node_id;
import util::interner;
import lexer::reader;

type parse_sess = @{
    cm: codemap::codemap,
    mut next_id: node_id,
    span_diagnostic: diagnostic::span_handler,
    // these two must be kept up to date
    mut chpos: uint,
    mut byte_pos: uint
};

fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) ->
   @ast::crate {
    if str::ends_with(input, ".rc") {
        parse_crate_from_crate_file(input, cfg, sess)
    } else if str::ends_with(input, ".rs") {
        parse_crate_from_source_file(input, cfg, sess)
    } else {
        sess.span_diagnostic.handler().fatal("unknown input file type: " +
                                             input)
    }
}

fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::CRATE_FILE);
    let lo = p.span.lo;
    let prefix = path::dirname(p.reader.filemap.name);
    let leading_attrs = p.parse_inner_attrs_and_next();
    let { inner: crate_attrs, next: first_cdir_attr } = leading_attrs;
    let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    let cx = @{sess: sess, cfg: /* FIXME: bad */ copy p.cfg};
    let (companionmod, _) = path::splitext(path::basename(input));
    let (m, attrs) = eval::eval_crate_directives_to_mod(
        cx, cdirs, prefix, option::some(companionmod));
    let mut hi = p.span.hi;
    p.expect(token::EOF);
    ret @ast_util::respan(ast_util::mk_sp(lo, hi),
                          {directives: cdirs,
                           module: m,
                           attrs: crate_attrs + attrs,
                           config: /* FIXME: bad */ copy p.cfg});
}

fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
                                sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::SOURCE_FILE);
    let r = p.parse_crate_mod(cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_crate_mod(cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_expr();
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_item_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              +attrs: [ast::attribute], vis: ast::visibility,
                              sess: parse_sess) -> option<@ast::item> {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_item(attrs, vis);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_from_source_str<T>(f: fn (p: parser) -> T,
                            name: str, ss: codemap::file_substr,
                            source: @str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss, source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal("expected end-of-string");
    }
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    ret rv;
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              +name: str, +ss: codemap::file_substr,
                              source: @str) -> parser {
    let ftype = parser::SOURCE_FILE;
    let filemap = codemap::new_filemap_w_substr
        (name, ss, source, sess.chpos, sess.byte_pos);
    sess.cm.files.push(filemap);
    let itr = @interner::mk::<@str>({|x|str::hash(*x)}, {|x,y|str::eq(*x, *y)});
    let rdr = lexer::new_reader(sess.span_diagnostic,
                                filemap, itr);
    ret parser(sess, cfg, rdr, ftype);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, +path: str,
                        ftype: parser::file_type) ->
   parser {
    let res = io::read_whole_file_str(path);
    alt res {
      result::ok(_) { /* Continue. */ }
      result::err(e) { sess.span_diagnostic.handler().fatal(e); }
    }
    let src = @result::unwrap(res);
    let filemap = codemap::new_filemap(path, src, sess.chpos, sess.byte_pos);
    sess.cm.files.push(filemap);
       let itr = @interner::mk::<@str>({|x|str::hash(*x)}, {|x,y|str::eq(*x, *y)});
    let rdr = lexer::new_reader(sess.span_diagnostic, filemap, itr);
    ret parser(sess, cfg, rdr, ftype);
}
<commit_msg>Fix long lines<commit_after>#[doc = "The main parser interface"];
import dvec::extensions;

export parse_sess;
export next_node_id;
export new_parser_from_file;
export new_parser_from_source_str;
export parse_crate_from_file;
export parse_crate_from_crate_file;
export parse_crate_from_source_str;
export parse_expr_from_source_str;
export parse_item_from_source_str;
export parse_from_source_str;

import parser::parser;
import attr::parser_attr;
import common::parser_common;
import ast::node_id;
import util::interner;
import lexer::reader;

type parse_sess = @{
    cm: codemap::codemap,
    mut next_id: node_id,
    span_diagnostic: diagnostic::span_handler,
    // these two must be kept up to date
    mut chpos: uint,
    mut byte_pos: uint
};

fn parse_crate_from_file(input: str, cfg: ast::crate_cfg, sess: parse_sess) ->
   @ast::crate {
    if str::ends_with(input, ".rc") {
        parse_crate_from_crate_file(input, cfg, sess)
    } else if str::ends_with(input, ".rs") {
        parse_crate_from_source_file(input, cfg, sess)
    } else {
        sess.span_diagnostic.handler().fatal("unknown input file type: " +
                                             input)
    }
}

fn parse_crate_from_crate_file(input: str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::CRATE_FILE);
    let lo = p.span.lo;
    let prefix = path::dirname(p.reader.filemap.name);
    let leading_attrs = p.parse_inner_attrs_and_next();
    let { inner: crate_attrs, next: first_cdir_attr } = leading_attrs;
    let cdirs = p.parse_crate_directives(token::EOF, first_cdir_attr);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    let cx = @{sess: sess, cfg: /* FIXME: bad */ copy p.cfg};
    let (companionmod, _) = path::splitext(path::basename(input));
    let (m, attrs) = eval::eval_crate_directives_to_mod(
        cx, cdirs, prefix, option::some(companionmod));
    let mut hi = p.span.hi;
    p.expect(token::EOF);
    ret @ast_util::respan(ast_util::mk_sp(lo, hi),
                          {directives: cdirs,
                           module: m,
                           attrs: crate_attrs + attrs,
                           config: /* FIXME: bad */ copy p.cfg});
}

fn parse_crate_from_source_file(input: str, cfg: ast::crate_cfg,
                                sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_file(sess, cfg, input, parser::SOURCE_FILE);
    let r = p.parse_crate_mod(cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_crate_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                               sess: parse_sess) -> @ast::crate {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_crate_mod(cfg);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_expr_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              sess: parse_sess) -> @ast::expr {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_expr();
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_item_from_source_str(name: str, source: @str, cfg: ast::crate_cfg,
                              +attrs: [ast::attribute], vis: ast::visibility,
                              sess: parse_sess) -> option<@ast::item> {
    let p = new_parser_from_source_str(
        sess, cfg, name, codemap::fss_none, source);
    let r = p.parse_item(attrs, vis);
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn parse_from_source_str<T>(f: fn (p: parser) -> T,
                            name: str, ss: codemap::file_substr,
                            source: @str, cfg: ast::crate_cfg,
                            sess: parse_sess)
    -> T
{
    let p = new_parser_from_source_str(sess, cfg, name, ss, source);
    let r = f(p);
    if !p.reader.is_eof() {
        p.reader.fatal("expected end-of-string");
    }
    sess.chpos = p.reader.chpos;
    sess.byte_pos = sess.byte_pos + p.reader.pos;
    ret r;
}

fn next_node_id(sess: parse_sess) -> node_id {
    let rv = sess.next_id;
    sess.next_id += 1;
    // ID 0 is reserved for the crate and doesn't actually exist in the AST
    assert rv != 0;
    ret rv;
}

fn new_parser_from_source_str(sess: parse_sess, cfg: ast::crate_cfg,
                              +name: str, +ss: codemap::file_substr,
                              source: @str) -> parser {
    let ftype = parser::SOURCE_FILE;
    let filemap = codemap::new_filemap_w_substr
        (name, ss, source, sess.chpos, sess.byte_pos);
    sess.cm.files.push(filemap);
    let itr = @interner::mk::<@str>(
        {|x|str::hash(*x)},
        {|x,y|str::eq(*x, *y)}
    );
    let rdr = lexer::new_reader(sess.span_diagnostic,
                                filemap, itr);
    ret parser(sess, cfg, rdr, ftype);
}

fn new_parser_from_file(sess: parse_sess, cfg: ast::crate_cfg, +path: str,
                        ftype: parser::file_type) ->
   parser {
    let res = io::read_whole_file_str(path);
    alt res {
      result::ok(_) { /* Continue. */ }
      result::err(e) { sess.span_diagnostic.handler().fatal(e); }
    }
    let src = @result::unwrap(res);
    let filemap = codemap::new_filemap(path, src, sess.chpos, sess.byte_pos);
    sess.cm.files.push(filemap);
    let itr = @interner::mk::<@str>(
        {|x|str::hash(*x)},
        {|x,y|str::eq(*x, *y)}
    );
    let rdr = lexer::new_reader(sess.span_diagnostic, filemap, itr);
    ret parser(sess, cfg, rdr, ftype);
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use num::{Float};
use cgmath::{perspective, rad, Matrix4, Vector, Vector3, Rad};
use common::types::{Size2, ZFloat};
use common::misc::{clamp};
use zgl::{Zgl};
use types::{WorldPos};

pub struct Camera {
    x_angle: Rad<ZFloat>,
    z_angle: Rad<ZFloat>,
    pos: WorldPos,
    max_pos: WorldPos,
    zoom: ZFloat,
    projection_mat: Matrix4<ZFloat>,
}

fn get_projection_mat(win_size: &Size2) -> Matrix4<ZFloat> {
    let fov = rad(PI / 4.0);
    let ratio = win_size.w as ZFloat / win_size.h as ZFloat;
    let display_range_min = 0.1;
    let display_range_max = 100.0;
    perspective(
        fov, ratio, display_range_min, display_range_max)
}

impl Camera {
    pub fn new(win_size: &Size2) -> Camera {
        Camera {
            x_angle: rad(PI / 4.0),
            z_angle: rad(0.0),
            pos: WorldPos{v: Vector::from_value(0.0)},
            max_pos: WorldPos{v: Vector::from_value(0.0)},
            zoom: 16.0,
            projection_mat: get_projection_mat(win_size),
        }
    }

    pub fn mat(&self, zgl: &Zgl) -> Matrix4<ZFloat> {
        let mut m = self.projection_mat;
        m = zgl.tr(m, &Vector3{x: 0.0, y: 0.0, z: -self.zoom});
        m = zgl.rot_x(m, &-self.x_angle);
        m = zgl.rot_z(m, &-self.z_angle);
        m = zgl.tr(m, &self.pos.v);
        m
    }

    pub fn add_horizontal_angle(&mut self, angle: Rad<ZFloat>) {
        self.z_angle = self.z_angle + angle;
        while self.z_angle < rad(0.0) {
            self.z_angle = self.z_angle + rad(PI * 2.0);
        }
        while self.z_angle > rad(PI * 2.0) {
            self.z_angle = self.z_angle - rad(PI * 2.0);
        }
    }

    pub fn add_vertical_angle(&mut self, angle: Rad<ZFloat>) {
        self.x_angle = self.x_angle + angle;
        let min = rad(PI / 18.0);
        let max = rad(PI / 4.0);
        self.x_angle = clamp(self.x_angle, min, max);
    }

    fn clamp_pos(&mut self) {
        self.pos.v.x = clamp(self.pos.v.x, self.max_pos.v.x, 0.0);
        self.pos.v.y = clamp(self.pos.v.y, self.max_pos.v.y, 0.0);
    }

    pub fn set_pos(&mut self, pos: WorldPos) {
        self.pos = pos;
        self.clamp_pos();
    }

    pub fn set_max_pos(&mut self, max_pos: WorldPos) {
        self.max_pos = max_pos;
    }

    pub fn change_zoom(&mut self, ratio: ZFloat) {
        self.zoom *= ratio;
        self.zoom = clamp(self.zoom, 5.0, 40.0);
    }

    pub fn get_z_angle(&self) -> &Rad<ZFloat> {
        &self.z_angle
    }

    pub fn get_x_angle(&self) -> &Rad<ZFloat> {
        &self.x_angle
    }

    // TODO: rename to 'move'
    pub fn move_camera(&mut self, angle: Rad<ZFloat>, speed: ZFloat) {
        let diff = (self.z_angle - angle).s;
        let dx = diff.sin();
        let dy = diff.cos();
        // TODO: handle zoom
        // self.pos.v.x -= dy * speed * self.zoom;
        // self.pos.v.y -= dx * speed * self.zoom;
        self.pos.v.x -= dy * speed;
        self.pos.v.y -= dx * speed;
        self.clamp_pos();
    }

    pub fn regenerate_projection_mat(&mut self, win_size: &Size2) {
        self.projection_mat = get_projection_mat(win_size);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>Tweaked cam<commit_after>// See LICENSE file for copyright and license details.

use std::f32::consts::{PI};
use num::{Float};
use cgmath::{perspective, rad, Matrix4, Vector, Vector3, Rad};
use common::types::{Size2, ZFloat};
use common::misc::{clamp};
use zgl::{Zgl};
use types::{WorldPos};

pub struct Camera {
    x_angle: Rad<ZFloat>,
    z_angle: Rad<ZFloat>,
    pos: WorldPos,
    max_pos: WorldPos,
    zoom: ZFloat,
    projection_mat: Matrix4<ZFloat>,
}

fn get_projection_mat(win_size: &Size2) -> Matrix4<ZFloat> {
    let fov = rad(PI / 4.0);
    let ratio = win_size.w as ZFloat / win_size.h as ZFloat;
    let display_range_min = 0.1;
    let display_range_max = 100.0;
    perspective(
        fov, ratio, display_range_min, display_range_max)
}

impl Camera {
    pub fn new(win_size: &Size2) -> Camera {
        Camera {
            x_angle: rad(PI / 4.0),
            z_angle: rad(0.0),
            pos: WorldPos{v: Vector::from_value(0.0)},
            max_pos: WorldPos{v: Vector::from_value(0.0)},
            zoom: 20.0,
            projection_mat: get_projection_mat(win_size),
        }
    }

    pub fn mat(&self, zgl: &Zgl) -> Matrix4<ZFloat> {
        let mut m = self.projection_mat;
        m = zgl.tr(m, &Vector3{x: 0.0, y: 0.0, z: -self.zoom});
        m = zgl.rot_x(m, &-self.x_angle);
        m = zgl.rot_z(m, &-self.z_angle);
        m = zgl.tr(m, &self.pos.v);
        m
    }

    pub fn add_horizontal_angle(&mut self, angle: Rad<ZFloat>) {
        self.z_angle = self.z_angle + angle;
        while self.z_angle < rad(0.0) {
            self.z_angle = self.z_angle + rad(PI * 2.0);
        }
        while self.z_angle > rad(PI * 2.0) {
            self.z_angle = self.z_angle - rad(PI * 2.0);
        }
    }

    pub fn add_vertical_angle(&mut self, angle: Rad<ZFloat>) {
        self.x_angle = self.x_angle + angle;
        let min = rad(PI / 18.0);
        let max = rad(PI / 4.0);
        self.x_angle = clamp(self.x_angle, min, max);
    }

    fn clamp_pos(&mut self) {
        self.pos.v.x = clamp(self.pos.v.x, self.max_pos.v.x, 0.0);
        self.pos.v.y = clamp(self.pos.v.y, self.max_pos.v.y, 0.0);
    }

    pub fn set_pos(&mut self, pos: WorldPos) {
        self.pos = pos;
        self.clamp_pos();
    }

    pub fn set_max_pos(&mut self, max_pos: WorldPos) {
        self.max_pos = max_pos;
    }

    pub fn change_zoom(&mut self, ratio: ZFloat) {
        self.zoom *= ratio;
        self.zoom = clamp(self.zoom, 10.0, 40.0);
    }

    pub fn get_z_angle(&self) -> &Rad<ZFloat> {
        &self.z_angle
    }

    pub fn get_x_angle(&self) -> &Rad<ZFloat> {
        &self.x_angle
    }

    // TODO: rename to 'move'
    pub fn move_camera(&mut self, angle: Rad<ZFloat>, speed: ZFloat) {
        let diff = (self.z_angle - angle).s;
        let dx = diff.sin();
        let dy = diff.cos();
        // TODO: handle zoom
        // self.pos.v.x -= dy * speed * self.zoom;
        // self.pos.v.y -= dx * speed * self.zoom;
        self.pos.v.x -= dy * speed;
        self.pos.v.y -= dx * speed;
        self.clamp_pos();
    }

    pub fn regenerate_projection_mat(&mut self, win_size: &Size2) {
        self.projection_mat = get_projection_mat(win_size);
    }
}

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use num::{One, Zero};
use alga::general::{ClosedDiv, SubsetOf, SupersetOf};

use base::{DefaultAllocator, Matrix, Scalar, VectorN};
use base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use base::allocator::Allocator;

use geometry::Point;
#[cfg(feature = "mint")]
use mint;
#[cfg(feature = "mint")]
use base::dimension::{U2, U3};
#[cfg(feature = "mint")]
use std::convert::{AsMut, AsRef, From, Into};
#[cfg(feature = "mint")]
use base::storage::{Storage, StorageMut};
#[cfg(feature = "mint")]
use std::mem;

/*
 * This file provides the following conversions:
 * =============================================
 *
 * Point -> Point
 * Point -> Vector (homogeneous)
 *
 * mint::Point <-> Point
 */

impl<N1, N2, D> SubsetOf<Point<N2, D>> for Point<N1, D>
where
    D: DimName,
    N1: Scalar,
    N2: Scalar + SupersetOf<N1>,
    DefaultAllocator: Allocator<N2, D> + Allocator<N1, D>,
{
    #[inline]
    fn to_superset(&self) -> Point<N2, D> {
        Point::from_coordinates(self.coords.to_superset())
    }

    #[inline]
    fn is_in_subset(m: &Point<N2, D>) -> bool {
        // FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of
        // SubsetOf?
        m.iter().all(|e| e.is_in_subset())
    }

    #[inline]
    unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self {
        Point::from_coordinates(Matrix::from_superset_unchecked(&m.coords))
    }
}

impl<N1, N2, D> SubsetOf<VectorN<N2, DimNameSum<D, U1>>> for Point<N1, D>
where
    D: DimNameAdd<U1>,
    N1: Scalar,
    N2: Scalar + Zero + One + ClosedDiv + SupersetOf<N1>,
    DefaultAllocator: Allocator<N1, D>
        + Allocator<N1, DimNameSum<D, U1>>
        + Allocator<N2, DimNameSum<D, U1>>
        + Allocator<N2, D>,
{
    #[inline]
    fn to_superset(&self) -> VectorN<N2, DimNameSum<D, U1>> {
        let p: Point<N2, D> = self.to_superset();
        p.to_homogeneous()
    }

    #[inline]
    fn is_in_subset(v: &VectorN<N2, DimNameSum<D, U1>>) -> bool {
        ::is_convertible::<_, VectorN<N1, DimNameSum<D, U1>>>(v) && !v[D::dim()].is_zero()
    }

    #[inline]
    unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self {
        let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
        Self::from_coordinates(::convert_unchecked(coords))
    }
}

#[cfg(feature = "mint")]
macro_rules! impl_from_into_mint_1D(
    ($($NRows: ident => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$(
        impl<N> From<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar,
              DefaultAllocator: Allocator<N, $NRows> {
            #[inline]
            fn from(p: mint::$PT<N>) -> Self {
                Self {
                    coords: VectorN::from(mint::$VT::from(p)),
                }
            }
        }

        impl<N> Into<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn into(self) -> mint::$PT<N> {
                let mint_vec: mint::$VT<N> = self.coords.into();
                mint::$PT::from(mint_vec)
            }
        }

        impl<N> AsRef<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn as_ref(&self) -> &mint::$PT<N> {
                unsafe {
                    mem::transmute(self.coords.data.ptr())
                }
            }
        }

        impl<N> AsMut<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn as_mut(&mut self) -> &mut mint::$PT<N> {
                unsafe {
                    mem::transmute(self.coords.data.ptr_mut())
                }
            }
        }
    )*}
);

// Implement for points of dimension 2, 3.
#[cfg(feature = "mint")]
impl_from_into_mint_1D!(
    U2 => Point2, Vector2[2];
    U3 => Point3, Vector3[3];
);
<commit_msg>Replace mem::transmute() with pointer casts<commit_after>use num::{One, Zero};
use alga::general::{ClosedDiv, SubsetOf, SupersetOf};

use base::{DefaultAllocator, Matrix, Scalar, VectorN};
use base::dimension::{DimName, DimNameAdd, DimNameSum, U1};
use base::allocator::Allocator;

use geometry::Point;
#[cfg(feature = "mint")]
use mint;
#[cfg(feature = "mint")]
use base::dimension::{U2, U3};
#[cfg(feature = "mint")]
use std::convert::{AsMut, AsRef, From, Into};
#[cfg(feature = "mint")]
use base::storage::{Storage, StorageMut};
/*
 * This file provides the following conversions:
 * =============================================
 *
 * Point -> Point
 * Point -> Vector (homogeneous)
 *
 * mint::Point <-> Point
 */

impl<N1, N2, D> SubsetOf<Point<N2, D>> for Point<N1, D>
where
    D: DimName,
    N1: Scalar,
    N2: Scalar + SupersetOf<N1>,
    DefaultAllocator: Allocator<N2, D> + Allocator<N1, D>,
{
    #[inline]
    fn to_superset(&self) -> Point<N2, D> {
        Point::from_coordinates(self.coords.to_superset())
    }

    #[inline]
    fn is_in_subset(m: &Point<N2, D>) -> bool {
        // FIXME: is there a way to reuse the `.is_in_subset` from the matrix implementation of
        // SubsetOf?
        m.iter().all(|e| e.is_in_subset())
    }

    #[inline]
    unsafe fn from_superset_unchecked(m: &Point<N2, D>) -> Self {
        Point::from_coordinates(Matrix::from_superset_unchecked(&m.coords))
    }
}

impl<N1, N2, D> SubsetOf<VectorN<N2, DimNameSum<D, U1>>> for Point<N1, D>
where
    D: DimNameAdd<U1>,
    N1: Scalar,
    N2: Scalar + Zero + One + ClosedDiv + SupersetOf<N1>,
    DefaultAllocator: Allocator<N1, D>
        + Allocator<N1, DimNameSum<D, U1>>
        + Allocator<N2, DimNameSum<D, U1>>
        + Allocator<N2, D>,
{
    #[inline]
    fn to_superset(&self) -> VectorN<N2, DimNameSum<D, U1>> {
        let p: Point<N2, D> = self.to_superset();
        p.to_homogeneous()
    }

    #[inline]
    fn is_in_subset(v: &VectorN<N2, DimNameSum<D, U1>>) -> bool {
        ::is_convertible::<_, VectorN<N1, DimNameSum<D, U1>>>(v) && !v[D::dim()].is_zero()
    }

    #[inline]
    unsafe fn from_superset_unchecked(v: &VectorN<N2, DimNameSum<D, U1>>) -> Self {
        let coords = v.fixed_slice::<D, U1>(0, 0) / v[D::dim()];
        Self::from_coordinates(::convert_unchecked(coords))
    }
}

#[cfg(feature = "mint")]
macro_rules! impl_from_into_mint_1D(
    ($($NRows: ident => $PT:ident, $VT:ident [$SZ: expr]);* $(;)*) => {$(
        impl<N> From<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar,
              DefaultAllocator: Allocator<N, $NRows> {
            #[inline]
            fn from(p: mint::$PT<N>) -> Self {
                Self {
                    coords: VectorN::from(mint::$VT::from(p)),
                }
            }
        }

        impl<N> Into<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn into(self) -> mint::$PT<N> {
                let mint_vec: mint::$VT<N> = self.coords.into();
                mint::$PT::from(mint_vec)
            }
        }

        impl<N> AsRef<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn as_ref(&self) -> &mint::$PT<N> {
                unsafe {
                    &*(self.coords.data.ptr() as *const mint::$PT<N>)
                }
            }
        }

        impl<N> AsMut<mint::$PT<N>> for Point<N, $NRows>
        where N: Scalar {
            #[inline]
            fn as_mut(&mut self) -> &mut mint::$PT<N> {
                unsafe {
                    &mut *(self.coords.data.ptr_mut() as *mut mint::$PT<N>)
                }
            }
        }
    )*}
);

// Implement for points of dimension 2, 3.
#[cfg(feature = "mint")]
impl_from_into_mint_1D!(
    U2 => Point2, Vector2[2];
    U3 => Point3, Vector3[3];
);
<|endoftext|>


<commit_before>use crate::document::Document;
use crate::key::Key;
use crate::parser::errors::CustomError;
use crate::parser::inline_table::KEYVAL_SEP;
use crate::parser::key::key;
use crate::parser::table::table;
use crate::parser::trivia::{comment, line_ending, line_trailing, newline, ws};
use crate::parser::value::value;
use crate::parser::{TomlError, TomlParser};
use crate::table::TableKeyValue;
use crate::{InternalString, Item};
use combine::parser::byte::byte;
use combine::stream::position::{IndexPositioner, Positioner, Stream};
use combine::stream::RangeStream;
use combine::Parser;
use combine::*;
use std::cell::RefCell;
use std::mem;
use std::ops::DerefMut;

toml_parser!(parse_comment, parser, {
    (comment(), line_ending()).and_then::<_, _, std::str::Utf8Error>(|(c, e)| {
        let c = std::str::from_utf8(c)?;
        parser.borrow_mut().deref_mut().on_comment(c, e);
        Ok(())
    })
});

toml_parser!(
    parse_ws,
    parser,
    ws().map(|w| parser.borrow_mut().deref_mut().on_ws(w))
);

toml_parser!(parse_newline, parser, {
    newline().map(|_| parser.borrow_mut().deref_mut().on_ws("\n"))
});

toml_parser!(keyval, parser, {
    parse_keyval().and_then(|(p, kv)| parser.borrow_mut().deref_mut().on_keyval(p, kv))
});

// keyval = key keyval-sep val
parser! {
    fn parse_keyval['a, I]()(I) -> (Vec<Key>, TableKeyValue)
    where
        [I: RangeStream<
         Range = &'a [u8],
         Token = u8>,
         I::Error: ParseError<u8, &'a [u8], <I as StreamOnce>::Position>,
         <I::Error as ParseError<u8, &'a [u8], <I as StreamOnce>::Position>>::StreamError:
         From<std::num::ParseIntError> +
         From<std::num::ParseFloatError> +
         From<std::str::Utf8Error> +
         From<crate::parser::errors::CustomError>
    ] {
        (
            key(),
            byte(KEYVAL_SEP),
            (ws(), value(), line_trailing())
        ).and_then::<_, _, std::str::Utf8Error>(|(key, _, v)| {
            let mut path = key;
            let key = path.pop().expect("grammar ensures at least 1");

            let (pre, v, suf) = v;
            let suf = std::str::from_utf8(suf)?;
            let v = v.decorated(pre, suf);
            Ok((
                path,
                TableKeyValue {
                    key,
                    value: Item::Value(v),
                }
            ))
        })
    }
}

impl TomlParser {
    // ;; TOML

    // toml = expression *( newline expression )

    // expression = ( ( ws comment ) /
    //                ( ws keyval ws [ comment ] ) /
    //                ( ws table ws [ comment ] ) /
    //                  ws )
    pub(crate) fn parse(s: &[u8]) -> Result<Document, TomlError> {
        // Remove BOM if present
        let s = s.strip_prefix(b"\xEF\xBB\xBF").unwrap_or(s);

        let mut parser = RefCell::new(Self::default());
        let input = Stream::new(s);

        let parsed = parse_ws(&parser)
            .with(choice((
                eof(),
                skip_many1(
                    look_ahead(any()).then(|e| {
                        dispatch!(e;
                            crate::parser::trivia::COMMENT_START_SYMBOL => parse_comment(&parser),
                            crate::parser::table::STD_TABLE_OPEN => table(&parser),
                            crate::parser::trivia::LF |
                            crate::parser::trivia::CR => parse_newline(&parser),
                            _ => keyval(&parser),
                        )
                    })
                    .skip(parse_ws(&parser)),
                ),
            )))
            .easy_parse(input);
        match parsed {
            Ok((_, ref rest)) if !rest.input.is_empty() => Err(TomlError::from_unparsed(
                (&rest.positioner
                    as &dyn Positioner<usize, Position = usize, Checkpoint = IndexPositioner>)
                    .position(),
                s,
            )),
            Ok(..) => {
                parser
                    .get_mut()
                    .finalize_table()
                    .map_err(|e| TomlError::custom(e.to_string()))?;
                let trailing = parser.borrow().trailing.as_str().into();
                parser.get_mut().document.trailing = trailing;
                Ok(parser.into_inner().document)
            }
            Err(e) => Err(TomlError::new(e, s)),
        }
    }

    fn on_ws(&mut self, w: &str) {
        self.trailing.push_str(w);
    }

    fn on_comment(&mut self, c: &str, e: &str) {
        self.trailing = [&self.trailing, c, e].concat();
    }

    fn on_keyval(&mut self, mut path: Vec<Key>, mut kv: TableKeyValue) -> Result<(), CustomError> {
        {
            let prefix = mem::take(&mut self.trailing);
            let first_key = if path.is_empty() {
                &mut kv.key
            } else {
                &mut path[0]
            };
            first_key
                .decor
                .set_prefix(prefix + first_key.decor.prefix().unwrap_or_default());
        }

        let table = &mut self.current_table;
        let table = Self::descend_path(table, &path, true)?;

        // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
        let mixed_table_types = table.is_dotted() == path.is_empty();
        if mixed_table_types {
            return Err(CustomError::DuplicateKey {
                key: kv.key.get().into(),
                table: None,
            });
        }

        let key: InternalString = kv.key.get_internal().into();
        let old = table.items.insert(key.clone(), kv);
        let duplicate_key = old.is_some();
        // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed"
        if duplicate_key {
            return Err(CustomError::DuplicateKey {
                key: key.as_str().into(),
                table: Some(self.current_table_path.clone()),
            });
        }

        Ok(())
    }
}
<commit_msg>use Entry api instead of key clone, part 2 (#324)<commit_after>use crate::document::Document;
use crate::key::Key;
use crate::parser::errors::CustomError;
use crate::parser::inline_table::KEYVAL_SEP;
use crate::parser::key::key;
use crate::parser::table::table;
use crate::parser::trivia::{comment, line_ending, line_trailing, newline, ws};
use crate::parser::value::value;
use crate::parser::{TomlError, TomlParser};
use crate::table::TableKeyValue;
use crate::{InternalString, Item};
use combine::parser::byte::byte;
use combine::stream::position::{IndexPositioner, Positioner, Stream};
use combine::stream::RangeStream;
use combine::Parser;
use combine::*;
use indexmap::map::Entry;
use std::cell::RefCell;
use std::mem;
use std::ops::DerefMut;

toml_parser!(parse_comment, parser, {
    (comment(), line_ending()).and_then::<_, _, std::str::Utf8Error>(|(c, e)| {
        let c = std::str::from_utf8(c)?;
        parser.borrow_mut().deref_mut().on_comment(c, e);
        Ok(())
    })
});

toml_parser!(
    parse_ws,
    parser,
    ws().map(|w| parser.borrow_mut().deref_mut().on_ws(w))
);

toml_parser!(parse_newline, parser, {
    newline().map(|_| parser.borrow_mut().deref_mut().on_ws("\n"))
});

toml_parser!(keyval, parser, {
    parse_keyval().and_then(|(p, kv)| parser.borrow_mut().deref_mut().on_keyval(p, kv))
});

// keyval = key keyval-sep val
parser! {
    fn parse_keyval['a, I]()(I) -> (Vec<Key>, TableKeyValue)
    where
        [I: RangeStream<
         Range = &'a [u8],
         Token = u8>,
         I::Error: ParseError<u8, &'a [u8], <I as StreamOnce>::Position>,
         <I::Error as ParseError<u8, &'a [u8], <I as StreamOnce>::Position>>::StreamError:
         From<std::num::ParseIntError> +
         From<std::num::ParseFloatError> +
         From<std::str::Utf8Error> +
         From<crate::parser::errors::CustomError>
    ] {
        (
            key(),
            byte(KEYVAL_SEP),
            (ws(), value(), line_trailing())
        ).and_then::<_, _, std::str::Utf8Error>(|(key, _, v)| {
            let mut path = key;
            let key = path.pop().expect("grammar ensures at least 1");

            let (pre, v, suf) = v;
            let suf = std::str::from_utf8(suf)?;
            let v = v.decorated(pre, suf);
            Ok((
                path,
                TableKeyValue {
                    key,
                    value: Item::Value(v),
                }
            ))
        })
    }
}

impl TomlParser {
    // ;; TOML

    // toml = expression *( newline expression )

    // expression = ( ( ws comment ) /
    //                ( ws keyval ws [ comment ] ) /
    //                ( ws table ws [ comment ] ) /
    //                  ws )
    pub(crate) fn parse(s: &[u8]) -> Result<Document, TomlError> {
        // Remove BOM if present
        let s = s.strip_prefix(b"\xEF\xBB\xBF").unwrap_or(s);

        let mut parser = RefCell::new(Self::default());
        let input = Stream::new(s);

        let parsed = parse_ws(&parser)
            .with(choice((
                eof(),
                skip_many1(
                    look_ahead(any()).then(|e| {
                        dispatch!(e;
                            crate::parser::trivia::COMMENT_START_SYMBOL => parse_comment(&parser),
                            crate::parser::table::STD_TABLE_OPEN => table(&parser),
                            crate::parser::trivia::LF |
                            crate::parser::trivia::CR => parse_newline(&parser),
                            _ => keyval(&parser),
                        )
                    })
                    .skip(parse_ws(&parser)),
                ),
            )))
            .easy_parse(input);
        match parsed {
            Ok((_, ref rest)) if !rest.input.is_empty() => Err(TomlError::from_unparsed(
                (&rest.positioner
                    as &dyn Positioner<usize, Position = usize, Checkpoint = IndexPositioner>)
                    .position(),
                s,
            )),
            Ok(..) => {
                parser
                    .get_mut()
                    .finalize_table()
                    .map_err(|e| TomlError::custom(e.to_string()))?;
                let trailing = parser.borrow().trailing.as_str().into();
                parser.get_mut().document.trailing = trailing;
                Ok(parser.into_inner().document)
            }
            Err(e) => Err(TomlError::new(e, s)),
        }
    }

    fn on_ws(&mut self, w: &str) {
        self.trailing.push_str(w);
    }

    fn on_comment(&mut self, c: &str, e: &str) {
        self.trailing = [&self.trailing, c, e].concat();
    }

    fn on_keyval(&mut self, mut path: Vec<Key>, mut kv: TableKeyValue) -> Result<(), CustomError> {
        {
            let prefix = mem::take(&mut self.trailing);
            let first_key = if path.is_empty() {
                &mut kv.key
            } else {
                &mut path[0]
            };
            first_key
                .decor
                .set_prefix(prefix + first_key.decor.prefix().unwrap_or_default());
        }

        let table = &mut self.current_table;
        let table = Self::descend_path(table, &path, true)?;

        // "Likewise, using dotted keys to redefine tables already defined in [table] form is not allowed"
        let mixed_table_types = table.is_dotted() == path.is_empty();
        if mixed_table_types {
            return Err(CustomError::DuplicateKey {
                key: kv.key.get().into(),
                table: None,
            });
        }

        let key: InternalString = kv.key.get_internal().into();
        match table.items.entry(key) {
            Entry::Vacant(o) => {
                o.insert(kv);
            }
            Entry::Occupied(o) => {
                // "Since tables cannot be defined more than once, redefining such tables using a [table] header is not allowed"
                return Err(CustomError::DuplicateKey {
                    key: o.key().as_str().into(),
                    table: Some(self.current_table_path.clone()),
                });
            }
        }

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