<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::iterator::Iterator;
use std::ascii::to_ascii_lower;
use cssparser::*;
use selectors;
use properties;
use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};
use media_queries;

pub struct Stylesheet {
    rules: ~[CSSRule],
    namespaces: NamespaceMap,
}

pub enum CSSRule {
    CSSStyleRule(StyleRule),
    CSSMediaRule(MediaRule),
}

pub struct StyleRule {
    selectors: ~[selectors::Selector],
    declarations: properties::PropertyDeclarationBlock,
}

fn parse_stylesheet(css: &str) -> Stylesheet {
    static STATE_CHARSET: uint = 1;
    static STATE_IMPORTS: uint = 2;
    static STATE_NAMESPACES: uint = 3;
    static STATE_BODY: uint = 4;
    let mut state: uint = STATE_CHARSET;

    let mut rules = ~[];
    let mut namespaces = NamespaceMap::new();

    for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
        let next_state;  // Unitialized to force each branch to set it.
        match rule {
            QualifiedRule(rule) => {
                next_state = STATE_BODY;
                parse_style_rule(rule, &mut rules, &namespaces)
            },
            AtRule(rule) => {
                let lower_name: &str = to_ascii_lower(rule.name);
                match lower_name {
                    "charset" => {
                        if state > STATE_CHARSET {
                            log_css_error(rule.location, "@charset must be the first rule")
                        }
                        // Valid @charset rules are just ignored
                        next_state = state;
                    },
                    "import" => {
                        if state > STATE_IMPORTS {
                            next_state = state;
                            log_css_error(rule.location,
                                          "@import must be before any rule but @charset")
                        } else {
                            next_state = STATE_IMPORTS;
                            log_css_error(rule.location, "@import is not supported yet")  // TODO
                        }
                    },
                    "namespace" => {
                        if state > STATE_NAMESPACES {
                            next_state = state;
                            log_css_error(
                                rule.location,
                                "@namespace must be before any rule but @charset and @import"
                            )
                        } else {
                            next_state = STATE_NAMESPACES;
                            parse_namespace_rule(rule, &mut namespaces)
                        }
                    },
                    _ => {
                        next_state = STATE_BODY;
                        parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
                    },
                }
            },
        }
        state = next_state;
    }
    Stylesheet{ rules: rules, namespaces: namespaces }
}

pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
                        namespaces: &NamespaceMap) {
    let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
    match selectors::parse_selector_list(prelude, namespaces) {
        Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
            selectors: selectors,
            declarations: properties::parse_property_declaration_list(block)
        })),
        None => log_css_error(location, "Unsupported CSS selector."),
    }
}

// lower_name is passed explicitly to avoid computing it twice.
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
                            parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap) {
    match lower_name {
        "media" => parse_media_rule(rule, parent_rules, namespaces),
        _ => log_css_error(rule.location, fmt!("Unsupported at-rule: @%s", lower_name))
    }
}

impl Stylesheet {
    fn iter_style_rules<'a>(&'a self, device: &'a media_queries::Device) -> StyleRuleIterator<'a> {
        StyleRuleIterator { device: device, stack: ~[(self.rules.as_slice(), 0)] }
    }
}

struct StyleRuleIterator<'self> {
    device: &'self media_queries::Device,
    // FIXME: I couldn’t get this to borrow-check with a stack of VecIterator
    stack: ~[(&'self [CSSRule], uint)],
}

impl<'self> Iterator<&'self StyleRule> for StyleRuleIterator<'self> {
    fn next(&mut self) -> Option<&'self StyleRule> {
        loop {
            match self.stack.pop_opt() {
                None => return None,
                Some((rule_list, i)) => {
                    if i + 1 < rule_list.len() {
                        self.stack.push((rule_list, i + 1))
                    }
                    match rule_list[i] {
                        CSSStyleRule(ref rule) => return Some(rule),
                        CSSMediaRule(ref rule) => {
                            if rule.media_queries.evaluate(self.device) {
                                self.stack.push((rule.rules.as_slice(), 0))
                            }
                        }
                    }
                }
            }
        }
    }
}
<commit_msg>Only allow one @charset rule.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::iterator::Iterator;
use std::ascii::to_ascii_lower;
use cssparser::*;
use selectors;
use properties;
use errors::{ErrorLoggerIterator, log_css_error};
use namespaces::{NamespaceMap, parse_namespace_rule};
use media_queries::{MediaRule, parse_media_rule};
use media_queries;

pub struct Stylesheet {
    rules: ~[CSSRule],
    namespaces: NamespaceMap,
}

pub enum CSSRule {
    CSSStyleRule(StyleRule),
    CSSMediaRule(MediaRule),
}

pub struct StyleRule {
    selectors: ~[selectors::Selector],
    declarations: properties::PropertyDeclarationBlock,
}

fn parse_stylesheet(css: &str) -> Stylesheet {
    static STATE_CHARSET: uint = 1;
    static STATE_IMPORTS: uint = 2;
    static STATE_NAMESPACES: uint = 3;
    static STATE_BODY: uint = 4;
    let mut state: uint = STATE_CHARSET;

    let mut rules = ~[];
    let mut namespaces = NamespaceMap::new();

    for rule in ErrorLoggerIterator(parse_stylesheet_rules(tokenize(css))) {
        let next_state;  // Unitialized to force each branch to set it.
        match rule {
            QualifiedRule(rule) => {
                next_state = STATE_BODY;
                parse_style_rule(rule, &mut rules, &namespaces)
            },
            AtRule(rule) => {
                let lower_name: &str = to_ascii_lower(rule.name);
                match lower_name {
                    "charset" => {
                        if state > STATE_CHARSET {
                            log_css_error(rule.location, "@charset must be the first rule")
                        }
                        // Valid @charset rules are just ignored
                        next_state = STATE_IMPORTS;
                    },
                    "import" => {
                        if state > STATE_IMPORTS {
                            next_state = state;
                            log_css_error(rule.location,
                                          "@import must be before any rule but @charset")
                        } else {
                            next_state = STATE_IMPORTS;
                            log_css_error(rule.location, "@import is not supported yet")  // TODO
                        }
                    },
                    "namespace" => {
                        if state > STATE_NAMESPACES {
                            next_state = state;
                            log_css_error(
                                rule.location,
                                "@namespace must be before any rule but @charset and @import"
                            )
                        } else {
                            next_state = STATE_NAMESPACES;
                            parse_namespace_rule(rule, &mut namespaces)
                        }
                    },
                    _ => {
                        next_state = STATE_BODY;
                        parse_nested_at_rule(lower_name, rule, &mut rules, &namespaces)
                    },
                }
            },
        }
        state = next_state;
    }
    Stylesheet{ rules: rules, namespaces: namespaces }
}

pub fn parse_style_rule(rule: QualifiedRule, parent_rules: &mut ~[CSSRule],
                        namespaces: &NamespaceMap) {
    let QualifiedRule{location: location, prelude: prelude, block: block} = rule;
    match selectors::parse_selector_list(prelude, namespaces) {
        Some(selectors) => parent_rules.push(CSSStyleRule(StyleRule{
            selectors: selectors,
            declarations: properties::parse_property_declaration_list(block)
        })),
        None => log_css_error(location, "Unsupported CSS selector."),
    }
}

// lower_name is passed explicitly to avoid computing it twice.
pub fn parse_nested_at_rule(lower_name: &str, rule: AtRule,
                            parent_rules: &mut ~[CSSRule], namespaces: &NamespaceMap) {
    match lower_name {
        "media" => parse_media_rule(rule, parent_rules, namespaces),
        _ => log_css_error(rule.location, fmt!("Unsupported at-rule: @%s", lower_name))
    }
}

impl Stylesheet {
    fn iter_style_rules<'a>(&'a self, device: &'a media_queries::Device) -> StyleRuleIterator<'a> {
        StyleRuleIterator { device: device, stack: ~[(self.rules.as_slice(), 0)] }
    }
}

struct StyleRuleIterator<'self> {
    device: &'self media_queries::Device,
    // FIXME: I couldn’t get this to borrow-check with a stack of VecIterator
    stack: ~[(&'self [CSSRule], uint)],
}

impl<'self> Iterator<&'self StyleRule> for StyleRuleIterator<'self> {
    fn next(&mut self) -> Option<&'self StyleRule> {
        loop {
            match self.stack.pop_opt() {
                None => return None,
                Some((rule_list, i)) => {
                    if i + 1 < rule_list.len() {
                        self.stack.push((rule_list, i + 1))
                    }
                    match rule_list[i] {
                        CSSStyleRule(ref rule) => return Some(rule),
                        CSSMediaRule(ref rule) => {
                            if rule.media_queries.evaluate(self.device) {
                                self.stack.push((rule.rules.as_slice(), 0))
                            }
                        }
                    }
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>extern crate cairo;
extern crate gdk;
extern crate gdk_pixbuf_sys as pixbuf;
extern crate gio_sys as gio;
extern crate itertools;
extern crate notty;
extern crate pangocairo;

mod image_renderer;
mod text_renderer;

use itertools::Itertools;

use notty::cfg;
use notty::datatypes::Color;
use notty::terminal::{CharCell, Terminal};

use self::image_renderer::ImageRenderer;
use self::text_renderer::TextRenderer;

pub struct Renderer {
    char_w: f64,
    char_h: f64,
    scroll: u32,
}

impl Renderer {
    pub fn new(canvas: &cairo::Context, scroll: u32) -> Renderer {
        let (char_w, char_h) = char_dimensions(canvas);
        Renderer { char_w: char_w, char_h: char_h, scroll: scroll }
    }

    pub fn reset_dimensions(&self, terminal: &mut Terminal, x_pix: u32, y_pix: u32) {
        terminal.set_winsize(x_pix / self.char_w as u32, y_pix / self.char_h as u32);
    }

    pub fn draw(&self, terminal: &Terminal, canvas: &cairo::Context) {
        let Color(r,g,b) = cfg::DEFAULT_BG;
        canvas.set_source_rgb(color(r), color(g), color(b));
        canvas.paint();

        let col_n = terminal.grid_width as usize;
        let rows = terminal.into_iter().skip(self.scroll as usize * col_n).chunks_lazy(col_n);

        for (y_pos, row) in rows.into_iter().enumerate() {
            let y_pix = y_pix(canvas, y_pos);
            let mut text = TextRenderer::new(0.0, y_pix);
            for (x_pos, cell) in row.enumerate() {
                match cell {
                    &CharCell::Empty(style)                             => text.push(' ', style),
                    &CharCell::Char(ch, style)                          => text.push(ch, style),
                    &CharCell::Grapheme(ref s, style)                   => text.push_str(s, style),
                    &CharCell::Extension(..)                            => { }
                    &CharCell::Image { ref data, width, style, ..}      => {
                        if (x_pos + width as usize) < col_n {
                            text.draw(canvas);
                            text = TextRenderer::new(x_pix(canvas, x_pos + width as usize), y_pix);
                        }
                        ImageRenderer::new(&data, style, x_pix(canvas, x_pos), y_pix).draw(canvas);
                    }
                }
            }
            text.draw(canvas);
        }
    }
}

fn char_dimensions(canvas: &cairo::Context) -> (f64, f64) {
    let f_extents = canvas.font_extents();
    (f_extents.max_x_advance, f_extents.height)
}

fn color(byte: u8) -> f64 {
    byte as f64 / 255.0
}

fn x_pix(canvas: &cairo::Context, position: usize) -> f64 {
    position as f64 * (canvas.font_extents().max_x_advance)
}

fn y_pix(canvas: &cairo::Context, position: usize) -> f64 {
    position as f64 * (canvas.font_extents().height)
}
<commit_msg>Fix text line spacing using font ascent and descent attributes.<commit_after>extern crate cairo;
extern crate gdk;
extern crate gdk_pixbuf_sys as pixbuf;
extern crate gio_sys as gio;
extern crate itertools;
extern crate notty;
extern crate pangocairo;

mod image_renderer;
mod text_renderer;

use itertools::Itertools;

use notty::cfg;
use notty::datatypes::Color;
use notty::terminal::{CharCell, Terminal};

use self::image_renderer::ImageRenderer;
use self::text_renderer::TextRenderer;

pub struct Renderer {
    char_w: f64,
    char_h: f64,
    scroll: u32,
}

impl Renderer {
    pub fn new(canvas: &cairo::Context, scroll: u32) -> Renderer {
        let (char_w, char_h) = char_dimensions(canvas);
        Renderer { char_w: char_w, char_h: char_h, scroll: scroll }
    }

    pub fn reset_dimensions(&self, terminal: &mut Terminal, x_pix: u32, y_pix: u32) {
        terminal.set_winsize(x_pix / self.char_w as u32, y_pix / self.char_h as u32);
    }

    pub fn draw(&self, terminal: &Terminal, canvas: &cairo::Context) {
        let Color(r,g,b) = cfg::DEFAULT_BG;
        canvas.set_source_rgb(color(r), color(g), color(b));
        canvas.paint();

        let col_n = terminal.grid_width as usize;
        let rows = terminal.into_iter().skip(self.scroll as usize * col_n).chunks_lazy(col_n);

        for (y_pos, row) in rows.into_iter().enumerate() {
            let y_pix = y_pix(canvas, y_pos);
            let mut text = TextRenderer::new(0.0, y_pix);
            for (x_pos, cell) in row.enumerate() {
                match cell {
                    &CharCell::Empty(style)                             => text.push(' ', style),
                    &CharCell::Char(ch, style)                          => text.push(ch, style),
                    &CharCell::Grapheme(ref s, style)                   => text.push_str(s, style),
                    &CharCell::Extension(..)                            => { }
                    &CharCell::Image { ref data, width, style, ..}      => {
                        if (x_pos + width as usize) < col_n {
                            text.draw(canvas);
                            text = TextRenderer::new(x_pix(canvas, x_pos + width as usize), y_pix);
                        }
                        ImageRenderer::new(&data, style, x_pix(canvas, x_pos), y_pix).draw(canvas);
                    }
                }
            }
            text.draw(canvas);
        }
    }
}

fn char_dimensions(canvas: &cairo::Context) -> (f64, f64) {
    let f_extents = canvas.font_extents();
    (f_extents.max_x_advance, f_extents.height)
}

fn color(byte: u8) -> f64 {
    byte as f64 / 255.0
}

fn x_pix(canvas: &cairo::Context, position: usize) -> f64 {
    position as f64 * (canvas.font_extents().max_x_advance)
}

fn y_pix(canvas: &cairo::Context, position: usize) -> f64 {
    let f_extents = canvas.font_extents();
    position as f64 * (f_extents.height + f_extents.ascent + f_extents.descent)
}
<|endoftext|>


<commit_before>//! A module to deserialize a `Message` as defined in a .proto file
//!
//! Creates the struct and implements a reader

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

use errors::Result;
use reader::BytesReader;
use writer::Writer;

/// A trait to handle deserialization based on parsed `Field`s
pub trait MessageWrite: Sized {
    /// Writes `Self` into W writer
    fn write_message<W: Write>(&self, _: &mut Writer<W>) -> Result<()> {
        Ok(())
    }

    /// Computes necessary binary size of self once serialized in protobuf
    fn get_size(&self) -> usize {
        0
    }

    /// Writes self into a file
    fn write_file<P: AsRef<Path>>(&self, p: P) -> Result<()> {
        let file = BufWriter::new(File::create(p)?);
        let mut writer = Writer::new(file);
        self.write_message(&mut writer)
    }
}

/// A trait to handle deserialization from protocol buffers.
pub trait MessageRead<'a>: Sized {
    /// Constructs an instance of `Self` by reading from the given bytes
    /// via the given reader.
    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self>;
}
<commit_msg>update MessageRead trait comments<commit_after>//! A module to deserialize a `Message` as defined in a .proto file
//!
//! Creates the struct and implements a reader

use std::fs::File;
use std::io::{BufWriter, Write};
use std::path::Path;

use errors::Result;
use reader::BytesReader;
use writer::Writer;

/// A trait to handle deserialization based on parsed `Field`s
pub trait MessageWrite: Sized {
    /// Writes `Self` into W writer
    fn write_message<W: Write>(&self, _: &mut Writer<W>) -> Result<()> {
        Ok(())
    }

    /// Computes necessary binary size of self once serialized in protobuf
    fn get_size(&self) -> usize {
        0
    }

    /// Writes self into a file
    fn write_file<P: AsRef<Path>>(&self, p: P) -> Result<()> {
        let file = BufWriter::new(File::create(p)?);
        let mut writer = Writer::new(file);
        self.write_message(&mut writer)
    }
}

/// A trait to handle deserialization from protocol buffers.
pub trait MessageRead<'a>: Sized {
    /// Constructs an instance of `Self` by reading from the given bytes
    /// via the given reader.
    ///
    /// It does NOT read message length first. If you want to read a variable
    /// length message, use `BytesReader::read_message` directly
    fn from_reader(r: &mut BytesReader, bytes: &'a [u8]) -> Result<Self>;
}
<|endoftext|>


<commit_before>use crate::cpp_code_generator;
use crate::database::CppCheckerAddResult;
use crate::database::CppCheckerEnv;
use crate::database::CppFfiItem;
use crate::database::CppFfiItemKind;
use crate::processor::ProcessingStep;
use crate::processor::ProcessorData;
use indicatif::ProgressBar;
use indicatif::ProgressStyle;
use log::debug;
use ritual_common::cpp_lib_builder::{
    c2r_cmake_vars, BuildType, CppLibBuilder, CppLibBuilderOutput,
};
use ritual_common::errors::{bail, Result};
use ritual_common::file_utils::{create_dir_all, create_file, path_to_str, remove_dir_all};
use ritual_common::target::current_target;
use ritual_common::utils::MapIfOk;
use std::path::Path;
use std::path::PathBuf;

fn check_snippet(
    main_cpp_path: &Path,
    builder: &CppLibBuilder,
    snippet: &Snippet,
) -> Result<CppLibBuilderOutput> {
    {
        let mut file = create_file(main_cpp_path)?;
        file.write("#include \"utils.h\"\n\n")?;
        match snippet.context {
            SnippetContext::Main => {
                file.write(format!("int main() {{\n{}\n}}\n", snippet.code))?;
            }
            SnippetContext::Global => {
                file.write(format!("{}\n\nint main() {{}}\n", snippet.code))?;
            }
        }
    }
    builder.run()
}

fn snippet_for_item(item: &CppFfiItem) -> Result<Snippet> {
    match item.kind {
        CppFfiItemKind::Function(ref cpp_ffi_function) => Ok(Snippet::new_global(
            cpp_code_generator::function_implementation(cpp_ffi_function)?,
        )),
        CppFfiItemKind::QtSlotWrapper(ref _qt_slot_wrapper) => {
            bail!("qt slot wrappers are not supported yet");
        }
    }
}

struct CppChecker<'b, 'a: 'b> {
    data: &'b mut ProcessorData<'a>,
    env: CppCheckerEnv,
    main_cpp_path: PathBuf,
    builder: CppLibBuilder,
}

enum SnippetContext {
    Main,
    Global,
}
struct Snippet {
    code: String,
    context: SnippetContext,
}

impl Snippet {
    fn new_in_main<S: Into<String>>(code: S) -> Snippet {
        Snippet {
            code: code.into(),
            context: SnippetContext::Main,
        }
    }
    fn new_global<S: Into<String>>(code: S) -> Snippet {
        Snippet {
            code: code.into(),
            context: SnippetContext::Global,
        }
    }
}

fn new_progress_bar(count: u64, message: &str) -> ProgressBar {
    let progress_bar = ProgressBar::new(count);
    progress_bar.set_style(ProgressStyle::default_bar().template("{pos}/{len} {msg} {wide_bar}"));
    progress_bar.set_message(message);
    progress_bar
}

struct PreliminaryTest {
    name: String,
    snippet: Snippet,
    expected: bool,
}

impl PreliminaryTest {
    fn new(name: &str, expected: bool, snippet: Snippet) -> Self {
        Self {
            name: name.into(),
            expected,
            snippet,
        }
    }
}

impl CppChecker<'_, '_> {
    fn run(&mut self) -> Result<()> {
        if !self
            .data
            .current_database
            .environments
            .iter()
            .any(|e| e == &self.env)
        {
            self.data
                .current_database
                .environments
                .push(self.env.clone());
        }

        self.run_tests()?;

        let total_count = self.data.current_database.cpp_items.len();
        let progress_bar = new_progress_bar(total_count as u64, "Checking items");

        let env = self.env.clone();
        for item in &mut self.data.current_database.cpp_items {
            progress_bar.inc(1);
            for ffi_item in &mut item.ffi_items {
                if ffi_item.checks.items.iter().any(|check| check.env == env) {
                    continue;
                }

                if let Ok(snippet) = snippet_for_item(ffi_item) {
                    let error_data =
                        match check_snippet(&self.main_cpp_path, &self.builder, &snippet)? {
                            CppLibBuilderOutput::Success => None, // no error
                            CppLibBuilderOutput::Fail(output) => {
                                Some(format!("build failed: {}", output.stderr))
                            }
                        };
                    let r = ffi_item.checks.add(&self.env, error_data.clone());
                    let change_text = match r {
                        CppCheckerAddResult::Added => "Added".to_string(),
                        CppCheckerAddResult::Unchanged => "Unchanged".to_string(),
                        CppCheckerAddResult::Changed { ref old } => {
                            format!("Changed! Old data for the same env: {:?}", old)
                        }
                    };

                    debug!(
                        "[cpp_checker_update] ffi_item = {:?}; snippet = {:?}; error = {:?}; {}",
                        ffi_item, snippet.code, error_data, change_text
                    );
                }
            }
        }

        Ok(())
    }

    fn run_tests(&mut self) -> Result<()> {
        let tests = &[
            PreliminaryTest::new(
                "hello world",
                true,
                Snippet::new_in_main("std::cout << \"Hello world\\n\";"),
            ),
            PreliminaryTest::new(
                "correct assertion",
                true,
                Snippet::new_in_main("assert(2 + 2 == 4);"),
            ),
            PreliminaryTest::new(
                "type traits",
                true,
                Snippet::new_in_main(
                    "\
                     class C1 {}; \n\
                     enum E1 {};  \n\
                     assert(std::is_class<C1>::value); \n\
                     assert(!std::is_class<E1>::value); \n\
                     assert(!std::is_enum<C1>::value); \n\
                     assert(std::is_enum<E1>::value); \
                     assert(sizeof(C1) > 0);\
                     assert(sizeof(E1) > 0);\n\
                     ",
                ),
            ),
            PreliminaryTest::new(
                "incorrect assertion in fn",
                true,
                Snippet::new_global("int f1() { assert(2 + 2 == 5); return 1; }"),
            ),
            PreliminaryTest::new("syntax error", false, Snippet::new_in_main("}")),
            PreliminaryTest::new(
                "incorrect assertion",
                false,
                Snippet::new_in_main("assert(2 + 2 == 5)"),
            ),
            PreliminaryTest::new("status code 1", false, Snippet::new_in_main("return 1;")),
        ];

        let progress_bar = new_progress_bar(tests.len() as u64, "Running preliminary tests");
        for test in tests {
            progress_bar.inc(1);
            self.check_preliminary_test(test)?;
            self.builder.skip_cmake = true;
        }

        Ok(())
    }

    fn check_preliminary_test(&self, test: &PreliminaryTest) -> Result<()> {
        match self.check_snippet(&test.snippet)? {
            CppLibBuilderOutput::Success => {
                if !test.expected {
                    bail!("Nevative test ({}) succeeded", test.name);
                }
            }
            CppLibBuilderOutput::Fail(output) => {
                if test.expected {
                    bail!("Positive test ({}) failed: {}", test.name, output.stderr);
                }
            }
        }
        Ok(())
    }

    fn check_snippet(&self, snippet: &Snippet) -> Result<CppLibBuilderOutput> {
        check_snippet(&self.main_cpp_path, &self.builder, snippet)
    }
}

fn run(data: &mut ProcessorData) -> Result<()> {
    let root_path = data.workspace.tmp_path()?.join("cpp_checker");
    if root_path.exists() {
        remove_dir_all(&root_path)?;
    }
    let src_path = root_path.join("src");
    create_dir_all(&src_path)?;
    create_file(src_path.join("CMakeLists.txt"))?
        .write(include_str!("../templates/cpp_checker/CMakeLists.txt"))?;
    create_file(src_path.join("utils.h"))?.write(format!(
        include_str!("../templates/cpp_checker/utils.h"),
        include_directives_code = data
            .config
            .include_directives()
            .map_if_ok(|d| -> Result<_> { Ok(format!("#include \"{}\"", path_to_str(d)?)) })?
            .join("\n")
    ))?;

    let mut build_paths = data.config.cpp_build_paths().clone();
    build_paths.apply_env();
    let builder = CppLibBuilder {
        cmake_source_dir: src_path.clone(),
        build_dir: root_path.join("build"),
        install_dir: None,
        num_jobs: Some(1),
        build_type: BuildType::Debug,
        cmake_vars: c2r_cmake_vars(
            &data.config.cpp_build_config().eval(&current_target())?,
            &build_paths,
            None,
        )?,
        capture_output: true,
        skip_cmake: false,
    };

    let env = CppCheckerEnv {
        target: current_target(),
        cpp_library_version: data.config.cpp_lib_version().map(|s| s.to_string()),
    };
    let mut checker = CppChecker {
        data,
        builder,
        main_cpp_path: src_path.join("main.cpp"),
        env,
    };

    checker.run()?;

    Ok(())
}

pub fn cpp_checker_step() -> ProcessingStep {
    ProcessingStep::new("cpp_checker", run)
}
<commit_msg>calculate list of snippets before checking them<commit_after>use crate::cpp_code_generator;
use crate::database::CppCheckerAddResult;
use crate::database::CppCheckerEnv;
use crate::database::CppFfiItem;
use crate::database::CppFfiItemKind;
use crate::processor::ProcessingStep;
use crate::processor::ProcessorData;
use indicatif::ProgressBar;
use indicatif::ProgressStyle;
use log::debug;
use ritual_common::cpp_lib_builder::{
    c2r_cmake_vars, BuildType, CppLibBuilder, CppLibBuilderOutput,
};
use ritual_common::errors::{bail, Result};
use ritual_common::file_utils::{create_dir_all, create_file, path_to_str, remove_dir_all};
use ritual_common::target::current_target;
use ritual_common::utils::MapIfOk;
use std::path::Path;
use std::path::PathBuf;

fn check_snippet(
    main_cpp_path: &Path,
    builder: &CppLibBuilder,
    snippet: &Snippet,
) -> Result<CppLibBuilderOutput> {
    {
        let mut file = create_file(main_cpp_path)?;
        file.write("#include \"utils.h\"\n\n")?;
        match snippet.context {
            SnippetContext::Main => {
                file.write(format!("int main() {{\n{}\n}}\n", snippet.code))?;
            }
            SnippetContext::Global => {
                file.write(format!("{}\n\nint main() {{}}\n", snippet.code))?;
            }
        }
    }
    builder.run()
}

fn snippet_for_item(item: &CppFfiItem) -> Result<Snippet> {
    match item.kind {
        CppFfiItemKind::Function(ref cpp_ffi_function) => Ok(Snippet::new_global(
            cpp_code_generator::function_implementation(cpp_ffi_function)?,
        )),
        CppFfiItemKind::QtSlotWrapper(ref _qt_slot_wrapper) => {
            bail!("qt slot wrappers are not supported yet");
        }
    }
}

struct CppChecker<'b, 'a: 'b> {
    data: &'b mut ProcessorData<'a>,
    env: CppCheckerEnv,
    main_cpp_path: PathBuf,
    builder: CppLibBuilder,
}

enum SnippetContext {
    Main,
    Global,
}
struct Snippet {
    code: String,
    context: SnippetContext,
}

struct SnippetWithIndexes {
    snippet: Snippet,
    cpp_item_index: usize,
    ffi_item_index: usize,
}

impl Snippet {
    fn new_in_main<S: Into<String>>(code: S) -> Snippet {
        Snippet {
            code: code.into(),
            context: SnippetContext::Main,
        }
    }
    fn new_global<S: Into<String>>(code: S) -> Snippet {
        Snippet {
            code: code.into(),
            context: SnippetContext::Global,
        }
    }
}

fn new_progress_bar(count: u64, message: &str) -> ProgressBar {
    let progress_bar = ProgressBar::new(count);
    progress_bar.set_style(ProgressStyle::default_bar().template("{pos}/{len} {msg} {wide_bar}"));
    progress_bar.set_message(message);
    progress_bar
}

struct PreliminaryTest {
    name: String,
    snippet: Snippet,
    expected: bool,
}

impl PreliminaryTest {
    fn new(name: &str, expected: bool, snippet: Snippet) -> Self {
        Self {
            name: name.into(),
            expected,
            snippet,
        }
    }
}

impl CppChecker<'_, '_> {
    fn run(&mut self) -> Result<()> {
        if !self
            .data
            .current_database
            .environments
            .iter()
            .any(|e| e == &self.env)
        {
            self.data
                .current_database
                .environments
                .push(self.env.clone());
        }

        let env = self.env.clone();
        let mut snippets = Vec::new();
        for (cpp_item_index, item) in self.data.current_database.cpp_items.iter().enumerate() {
            for (ffi_item_index, ffi_item) in item.ffi_items.iter().enumerate() {
                if ffi_item.checks.items.iter().any(|check| check.env == env) {
                    continue;
                }

                if let Ok(snippet) = snippet_for_item(ffi_item) {
                    snippets.push(SnippetWithIndexes {
                        cpp_item_index,
                        ffi_item_index,
                        snippet,
                    });
                }
            }
        }

        if snippets.is_empty() {
            return Ok(());
        }

        self.run_tests()?;

        let progress_bar = new_progress_bar(snippets.len() as u64, "Checking items");
        for snippet in snippets {
            progress_bar.inc(1);
            let output = check_snippet(&self.main_cpp_path, &self.builder, &snippet.snippet)?;
            let error_data = match output {
                CppLibBuilderOutput::Success => None, // no error
                CppLibBuilderOutput::Fail(output) => {
                    Some(format!("build failed: {}", output.stderr))
                }
            };

            let cpp_item = &mut self.data.current_database.cpp_items[snippet.cpp_item_index];
            let ffi_item = &mut cpp_item.ffi_items[snippet.ffi_item_index];

            let r = ffi_item.checks.add(&self.env, error_data.clone());
            let change_text = match r {
                CppCheckerAddResult::Added => "Added".to_string(),
                CppCheckerAddResult::Unchanged => "Unchanged".to_string(),
                CppCheckerAddResult::Changed { ref old } => {
                    format!("Changed! Old data for the same env: {:?}", old)
                }
            };

            debug!(
                "[cpp_checker_update] ffi_item = {:?}; snippet = {:?}; error = {:?}; {}",
                ffi_item, snippet.snippet.code, error_data, change_text
            );
        }

        Ok(())
    }

    fn run_tests(&mut self) -> Result<()> {
        let tests = &[
            PreliminaryTest::new(
                "hello world",
                true,
                Snippet::new_in_main("std::cout << \"Hello world\\n\";"),
            ),
            PreliminaryTest::new(
                "correct assertion",
                true,
                Snippet::new_in_main("assert(2 + 2 == 4);"),
            ),
            PreliminaryTest::new(
                "type traits",
                true,
                Snippet::new_in_main(
                    "\
                     class C1 {}; \n\
                     enum E1 {};  \n\
                     assert(std::is_class<C1>::value); \n\
                     assert(!std::is_class<E1>::value); \n\
                     assert(!std::is_enum<C1>::value); \n\
                     assert(std::is_enum<E1>::value); \
                     assert(sizeof(C1) > 0);\
                     assert(sizeof(E1) > 0);\n\
                     ",
                ),
            ),
            PreliminaryTest::new(
                "incorrect assertion in fn",
                true,
                Snippet::new_global("int f1() { assert(2 + 2 == 5); return 1; }"),
            ),
            PreliminaryTest::new("syntax error", false, Snippet::new_in_main("}")),
            PreliminaryTest::new(
                "incorrect assertion",
                false,
                Snippet::new_in_main("assert(2 + 2 == 5)"),
            ),
            PreliminaryTest::new("status code 1", false, Snippet::new_in_main("return 1;")),
        ];

        let progress_bar = new_progress_bar(tests.len() as u64, "Running preliminary tests");
        for test in tests {
            progress_bar.inc(1);
            self.check_preliminary_test(test)?;
            self.builder.skip_cmake = true;
        }

        Ok(())
    }

    fn check_preliminary_test(&self, test: &PreliminaryTest) -> Result<()> {
        match self.check_snippet(&test.snippet)? {
            CppLibBuilderOutput::Success => {
                if !test.expected {
                    bail!("Nevative test ({}) succeeded", test.name);
                }
            }
            CppLibBuilderOutput::Fail(output) => {
                if test.expected {
                    bail!("Positive test ({}) failed: {}", test.name, output.stderr);
                }
            }
        }
        Ok(())
    }

    fn check_snippet(&self, snippet: &Snippet) -> Result<CppLibBuilderOutput> {
        check_snippet(&self.main_cpp_path, &self.builder, snippet)
    }
}

fn run(data: &mut ProcessorData) -> Result<()> {
    let root_path = data.workspace.tmp_path()?.join("cpp_checker");
    if root_path.exists() {
        remove_dir_all(&root_path)?;
    }
    let src_path = root_path.join("src");
    create_dir_all(&src_path)?;
    create_file(src_path.join("CMakeLists.txt"))?
        .write(include_str!("../templates/cpp_checker/CMakeLists.txt"))?;
    create_file(src_path.join("utils.h"))?.write(format!(
        include_str!("../templates/cpp_checker/utils.h"),
        include_directives_code = data
            .config
            .include_directives()
            .map_if_ok(|d| -> Result<_> { Ok(format!("#include \"{}\"", path_to_str(d)?)) })?
            .join("\n")
    ))?;

    let mut build_paths = data.config.cpp_build_paths().clone();
    build_paths.apply_env();
    let builder = CppLibBuilder {
        cmake_source_dir: src_path.clone(),
        build_dir: root_path.join("build"),
        install_dir: None,
        num_jobs: Some(1),
        build_type: BuildType::Debug,
        cmake_vars: c2r_cmake_vars(
            &data.config.cpp_build_config().eval(&current_target())?,
            &build_paths,
            None,
        )?,
        capture_output: true,
        skip_cmake: false,
    };

    let env = CppCheckerEnv {
        target: current_target(),
        cpp_library_version: data.config.cpp_lib_version().map(|s| s.to_string()),
    };
    let mut checker = CppChecker {
        data,
        builder,
        main_cpp_path: src_path.join("main.cpp"),
        env,
    };

    checker.run()?;

    Ok(())
}

pub fn cpp_checker_step() -> ProcessingStep {
    ProcessingStep::new("cpp_checker", run)
}
<|endoftext|>


<commit_before>extern crate gcc;

use std::io::prelude::*;
use std::fs;
use std::fs::File;

use std::process::Command;
use std::path::Path;

use std::env;

pub struct CuckooBuildEnv {

}

impl CuckooBuildEnv {

    pub fn new()->CuckooBuildEnv{
        CuckooBuildEnv {

        }
    }

    pub fn fail_on_empty_directory(&mut self, name: &str) {
        if fs::read_dir(name).unwrap().count() == 0 {
            println!("The `{}` directory is empty, did you forget to pull the submodules?", name);
            println!("Try `git submodule update --init --recursive`");
            panic!();
        }
    }

    pub fn build_cuckoo(&mut self, sources:String, variation: &str, size:u16) {

        self.fail_on_empty_directory("../../cuckoo");

        println!("Current Directory: {}", env::current_dir().unwrap().display());

        println!("cargo:rerun-if-changed=build.rs");
        println!("cargo:rerun-if-changed=../../cuckoo/src");

        let mut config = gcc::Config::new();
        config.include("../../cuckoo/src");
        config.include("../../cuckoo/src/cuckoo_miner");
        config.include(".");

        //Leave this here for now, config defines go here
        config.define("NDEBUG", Some("1"));

        let mut file = File::open(sources).expect("Unable to open the file");
        let mut contents = String::new();
        file.read_to_string(&mut contents).expect("Unable to read the file");
        //println!("{}", contents);

        let lib_sources = contents
            .split(" ")
            .collect::<Vec<&str>>();

        if cfg!(target_env = "msvc") {
            config.flag("-EHsc");
        } else {
            //config.flag("-Wall");
            config.flag("-D_POSIX_C_SOURCE=200112L");
            config.flag("-O3");
            config.flag("-std=c++11");
            config.flag("-march=native");
            config.flag("-m64");

            //config.flag("-mavx2");
            //config.flag("-DNSIPHASH=8");
        }

        for filename in lib_sources {
            let filepath = "../../cuckoo/src/".to_string() + &filename;
            config.file(&filepath);
        }

        config.flag(format!("-DEDGEBITS={}",size-1).as_str());
        config.flag("-DATOMIC");

        config.cpp(true);
        config.shared_flag(true);
        config.compile(format!("libcuckoo_{}_{}.a",variation,size).as_str());
    }

}<commit_msg>Fix to build to ensure generated object files don't conflict with each other.<commit_after>extern crate gcc;

use std::io::prelude::*;
use std::fs;
use std::fs::File;

use std::process::Command;
use std::path::Path;

use std::env;

pub struct CuckooBuildEnv {

}

impl CuckooBuildEnv {

    pub fn new()->CuckooBuildEnv{
        CuckooBuildEnv {

        }
    }

    pub fn fail_on_empty_directory(&mut self, name: &str) {
        if fs::read_dir(name).unwrap().count() == 0 {
            println!("The `{}` directory is empty, did you forget to pull the submodules?", name);
            println!("Try `git submodule update --init --recursive`");
            panic!();
        }
    }

    pub fn build_cuckoo(&mut self, sources:String, variation: &str, size:u16) {

        self.fail_on_empty_directory("../../cuckoo");

        println!("Current Directory: {}", env::current_dir().unwrap().display());

        println!("cargo:rerun-if-changed=build.rs");
        println!("cargo:rerun-if-changed=../../cuckoo/src");

        let mut config = gcc::Config::new();
        config.include("../../cuckoo/src");
        config.include("../../cuckoo/src/cuckoo_miner");
        config.include(".");

        //Leave this here for now, config defines go here
        config.define("NDEBUG", Some("1"));

        let mut file = File::open(sources).expect("Unable to open the file");
        let mut contents = String::new();
        file.read_to_string(&mut contents).expect("Unable to read the file");
        //println!("{}", contents);

        let lib_sources = contents
            .split(" ")
            .collect::<Vec<&str>>();

        if cfg!(target_env = "msvc") {
            config.flag("-EHsc");
        } else {
            //config.flag("-Wall");
            config.flag("-D_POSIX_C_SOURCE=200112L");
            config.flag("-O3");
            config.flag("-std=c++11");
            config.flag("-march=native");
            config.flag("-m64");

            //config.flag("-mavx2");
            //config.flag("-DNSIPHASH=8");
        }

        for filename in lib_sources {
            let filepath = "../../cuckoo/src/".to_string() + &filename;
            config.file(&filepath);
        }

        config.flag(format!("-DEDGEBITS={}",size-1).as_str());
        config.flag("-DATOMIC");

        //Have to change the output dir, to ensure generated
        //object files from each build don't overwrite each other
        let out_dir = env::var("OUT_DIR").unwrap();
        println!("{}", out_dir);
        let modded_out_dir = format!("{}/cuckoo-{}" ,out_dir, size);
        config.out_dir(Path::new(&modded_out_dir));

        config.cpp(true);
        config.shared_flag(true);
        config.compile(format!("libcuckoo_{}_{}.a",variation,size).as_str());
    }

}<|endoftext|>


<commit_before>use bit_vec::BitVec;
use lru_cache::LruCache;

use cache::AssetLoadContext;
use coordinates;

use std::cell::RefCell;
use std::collections::HashSet;
use std::f64::consts::PI;
use std::ops::Index;
use std::rc::Rc;

pub trait Scalar: Copy + 'static {
    fn from_f64(f64) -> Self;
    fn to_f64(self) -> f64;
}

/// Wrapper around BitVec that converts values to f64's so that it can be uses as a backing for a
/// GlobalRaster.
pub struct BitContainer(pub BitVec<u32>);
impl Index<usize> for BitContainer {
    type Output = f64;
    fn index(&self, i: usize) -> &f64 {
        if self.0[i] {
            &255.0
        } else {
            &0.0
        }
    }
}

/// Currently assumes that values are taken at the lower left corner of each cell.
#[derive(Clone, Serialize, Deserialize)]
pub struct Raster<T: Into<f64> + Copy> {
    pub width: usize,
    pub height: usize,
    pub cell_size: f64,

    pub xllcorner: f64,
    pub yllcorner: f64,

    pub values: Vec<T>,
}

impl<T: Into<f64> + Copy> Raster<T> {
    /// Returns the vertical spacing between cells, in meters.
    pub fn vertical_spacing(&self) -> f64 {
        self.cell_size.to_radians() * coordinates::PLANET_RADIUS
    }

    /// Returns the horizontal spacing between cells, in meters.
    pub fn horizontal_spacing(&self, x: usize) -> f64 {
        self.vertical_spacing()
            * (self.yllcorner + self.cell_size * x as f64)
                .to_radians()
                .cos()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64) -> Option<f64> {
        let x = (latitude - self.xllcorner) / self.cell_size;
        let y = (longitude - self.yllcorner) / self.cell_size;

        let y = (self.height - 1) as f64 - y;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;
        if x < 0.0 || fx >= self.width - 1 || y < 0.0 || fy >= self.height - 1 {
            return None;
        }

        let h00 = self.values[fx + fy * self.width].into();
        let h10 = self.values[fx + 1 + fy * self.width].into();
        let h01 = self.values[fx + (fy + 1) * self.width].into();
        let h11 = self.values[fx + 1 + (fy + 1) * self.width].into();
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        Some(h0 + (h1 - h0) * (x - fx as f64))
    }

    pub fn ambient_occlusion(&self) -> Raster<u8> {
        // See: https://nothings.org/gamedev/horizon

        let mut output = Raster {
            width: self.width,
            height: self.height,
            cell_size: self.cell_size,
            xllcorner: self.xllcorner,
            yllcorner: self.yllcorner,
            values: vec![0; self.width * self.height],
        };

        let mut walk =
            |mut x: usize, mut y: usize, dx: isize, dy: isize, steps: usize, step_size: f64| {
                let mut hull = Vec::new();
                for i in 0..(steps as isize) {
                    let h: f64 = self.values[x + y * self.width].into();
                    if hull.is_empty() {
                        hull.push((-1, h));
                    }

                    while hull.len() >= 2 {
                        let (i1, h1) = hull[hull.len() - 1];
                        let (i2, h2) = hull[hull.len() - 2];
                        if ((h1 - h) * (i - i2) as f64) < ((h2 - h) * (i - i1) as f64) {
                            hull.pop();
                        } else {
                            break;
                        }
                    }

                    let (i1, h1) = hull[hull.len() - 1];
                    let slope = (h1 - h) / ((i - i1) as f64 * step_size);
                    let occlusion: f64 = 1.0 - (slope.atan() / (0.5 * PI)).max(0.0);

                    hull.push((i, h));
                    output.values[x + y * self.width] += (occlusion * 63.75) as u8;
                    x = (x as isize + dx) as usize;
                    y = (y as isize + dy) as usize;
                }
            };

        for x in 0..self.width {
            let spacing = self.horizontal_spacing(x);
            walk(x, 0, 0, 1, self.height, spacing);
            walk(x, self.height - 1, 0, -1, self.height, spacing);
        }
        for y in 0..self.height {
            let spacing = self.vertical_spacing();
            walk(0, y, 1, 0, self.width, spacing);
            walk(self.width - 1, y, -1, 0, self.width, spacing);
        }

        output
    }
}

pub(crate) trait RasterSource {
    type Type: Into<f64> + Copy;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<Self::Type>>;
}

#[allow(unused)]
pub(crate) struct AmbientOcclusionSource<T: Into<f64> + Copy + 'static>(
    pub(crate) Rc<RefCell<RasterCache<T>>>,
);
impl<T: Into<f64> + Copy + 'static> RasterSource for AmbientOcclusionSource<T> {
    type Type = u8;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<u8>> {
        self.0
            .borrow_mut()
            .get(context, latitude, longitude)
            .map(|raster| raster.ambient_occlusion())
    }
}

#[derive(Copy, Clone)]
pub(crate) enum Axis {
    X,
    Y,
}
pub(crate) struct BlurredSource {
    cache: Rc<RefCell<RasterCache<u8>>>,
    sigma: f64,
    axis: Axis,
}
impl BlurredSource {
    pub fn new(cache: Rc<RefCell<RasterCache<u8>>>, sigma: f64) -> Self {
        Self {
            cache: Rc::new(RefCell::new(RasterCache::new(
                Box::new(Self {
                    cache,
                    axis: Axis::X,
                    sigma,
                }),
                512,
            ))),
            axis: Axis::Y,
            sigma,
        }
    }
}
impl RasterSource for BlurredSource {
    type Type = u8;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<u8>> {
        let mut values = Vec::new();

        let guassian = |x: f64| f64::exp(-0.5 * x * x);

        let mut cache = self.cache.borrow_mut();

        let (inner0, inner, inner2) = match self.axis {
            Axis::X => {
                let inner0 = cache.get(context, latitude - 1, longitude).cloned();
                let inner = cache.get(context, latitude, longitude)?.clone();
                let inner2 = cache.get(context, latitude + 1, longitude).cloned();
                (inner0, inner, inner2)
            }
            Axis::Y => {
                let inner0 = cache.get(context, latitude, (longitude - 1) % 180).cloned();
                let inner = cache.get(context, latitude, longitude)?.clone();
                let inner2 = cache.get(context, latitude, (longitude + 1) % 180).cloned();
                (inner0, inner, inner2)
            }
        };

        let max_three_sigma = self.sigma * 3.0 / inner.vertical_spacing();
        if max_three_sigma < 1.0 {
            return Some(inner);
        }

        for adjacent in [&inner0, &inner2].iter() {
            if let Some(ref adjacent) = *adjacent {
                assert_eq!(adjacent.width, inner.width);
                assert_eq!(adjacent.height, inner.height);
                assert_eq!(adjacent.cell_size, inner.cell_size);
            }
        }

        let iwidth = inner.width as isize;
        let iheight = inner.height as isize;
        let step = match self.axis {
            Axis::X => 1,
            Axis::Y => iwidth,
        };
        for y in 0..iheight {
            for x in 0..iwidth {
                let mut v = 0.0;
                let mut d = 0.0;
                let spacing = match self.axis {
                    Axis::X => inner.vertical_spacing(),
                    Axis::Y => inner.horizontal_spacing(x as usize),
                };
                let three_sigma = (self.sigma * 3.0 / spacing).floor() as isize;

                let min_offset = match (inner0.as_ref(), self.axis) {
                    (Some(_), _) => -three_sigma,
                    (None, Axis::X) => -three_sigma.min(x),
                    (None, Axis::Y) => -three_sigma.min(y),
                };
                let max_offset = match (inner2.as_ref(), self.axis) {
                    (Some(_), _) => three_sigma,
                    (None, Axis::X) => three_sigma.min(iwidth - x - 1),
                    (None, Axis::Y) => three_sigma.min(iheight - y - 1),
                };

                for offset in min_offset..=max_offset {
                    let i = x + y * iwidth + offset * step;

                    let (raster, i) = if i < 0 {
                        (inner0.as_ref().unwrap(), (i + iwidth * iheight) as usize)
                    } else if i >= iwidth * iheight {
                        (inner2.as_ref().unwrap(), (i - iwidth * iheight) as usize)
                    } else {
                        (&inner, i as usize)
                    };

                    let g = guassian(offset as f64 * spacing / self.sigma);
                    v += g * raster.values[i] as f64;
                    d += g;
                }
                v /= d;
                assert!(v < 255.5);
                values.push(v as u8);
            }
        }

        Some(Raster { values, ..inner })
    }
}

pub(crate) struct RasterCache<T: Into<f64> + Copy> {
    source: Box<RasterSource<Type = T>>,
    holes: HashSet<(i16, i16)>,
    rasters: LruCache<(i16, i16), Raster<T>>,
}
impl<T: Into<f64> + Copy> RasterCache<T> {
    pub fn new(source: Box<RasterSource<Type = T>>, size: usize) -> Self {
        Self {
            source,
            holes: HashSet::new(),
            rasters: LruCache::new(size),
        }
    }
    pub fn get(
        &mut self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<&mut Raster<T>> {
        let key = (latitude, longitude);
        if self.holes.contains(&key) {
            return None;
        }
        if let Some(dem) = self.rasters.get_mut(&key) {
            return Some(dem);
        }
        match self.source.load(context, key.0, key.1) {
            Some(raster) => {
                self.rasters.insert(key, raster);
                return self.rasters.get_mut(&key);
            }
            None => {
                self.holes.insert(key);
                None
            }
        }
    }
    pub fn interpolate(
        &mut self,
        context: &mut AssetLoadContext,
        latitude: f64,
        longitude: f64,
    ) -> Option<f64> {
        self.get(context, latitude.floor() as i16, longitude.floor() as i16)
            .and_then(|raster| raster.interpolate(latitude, longitude))
    }
}

/// Currently assumes that values are taken at the *center* of cells.
pub(crate) struct GlobalRaster<T: Into<f64> + Copy, C: Index<usize, Output = T> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub values: C,
}
impl<T: Into<f64> + Copy, C: Index<usize, Output = T>> GlobalRaster<T, C> {
    /// Returns the approximate grid spacing in meters.
    pub fn spacing(&self) -> f64 {
        let sx = 2.0 * PI * coordinates::PLANET_RADIUS / self.width as f64;
        let sy = PI * coordinates::PLANET_RADIUS / self.height as f64;
        sx.min(sy)
    }

    fn get(&self, x: i64, y: i64, band: usize) -> f64 {
        let y = y.max(0).min(self.height as i64) as usize;
        let x = (((x % self.width as i64) + self.width as i64) % self.width as i64) as usize;
        self.values[(x + y * self.width) * self.bands + band].into()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> f64 {
        assert!(latitude >= -90.0 && latitude <= 90.0);

        let x = (longitude + 180.0) / 360.0 * self.width as f64 - 0.5;
        let y = (90.0 - latitude) / 180.0 * self.height as f64 - 0.5;

        let fx = x.floor() as i64;
        let fy = y.floor() as i64;

        let h00 = self.get(fx, fy, band);
        let h10 = self.get(fx + 1, fy, band);
        let h01 = self.get(fx, fy + 1, band);
        let h11 = self.get(fx + 1, fy + 1, band);
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        h0 + (h1 - h0) * (x - fx as f64)
    }
}
<commit_msg>Make the borrow checker happy<commit_after>use bit_vec::BitVec;
use lru_cache::LruCache;

use cache::AssetLoadContext;
use coordinates;

use std::cell::RefCell;
use std::collections::HashSet;
use std::f64::consts::PI;
use std::ops::Index;
use std::rc::Rc;

pub trait Scalar: Copy + 'static {
    fn from_f64(f64) -> Self;
    fn to_f64(self) -> f64;
}

/// Wrapper around BitVec that converts values to f64's so that it can be uses as a backing for a
/// GlobalRaster.
pub struct BitContainer(pub BitVec<u32>);
impl Index<usize> for BitContainer {
    type Output = f64;
    fn index(&self, i: usize) -> &f64 {
        if self.0[i] {
            &255.0
        } else {
            &0.0
        }
    }
}

/// Currently assumes that values are taken at the lower left corner of each cell.
#[derive(Clone, Serialize, Deserialize)]
pub struct Raster<T: Into<f64> + Copy> {
    pub width: usize,
    pub height: usize,
    pub cell_size: f64,

    pub xllcorner: f64,
    pub yllcorner: f64,

    pub values: Vec<T>,
}

impl<T: Into<f64> + Copy> Raster<T> {
    /// Returns the vertical spacing between cells, in meters.
    pub fn vertical_spacing(&self) -> f64 {
        self.cell_size.to_radians() * coordinates::PLANET_RADIUS
    }

    /// Returns the horizontal spacing between cells, in meters.
    pub fn horizontal_spacing(&self, x: usize) -> f64 {
        self.vertical_spacing()
            * (self.yllcorner + self.cell_size * x as f64)
                .to_radians()
                .cos()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64) -> Option<f64> {
        let x = (latitude - self.xllcorner) / self.cell_size;
        let y = (longitude - self.yllcorner) / self.cell_size;

        let y = (self.height - 1) as f64 - y;

        let fx = x.floor() as usize;
        let fy = y.floor() as usize;
        if x < 0.0 || fx >= self.width - 1 || y < 0.0 || fy >= self.height - 1 {
            return None;
        }

        let h00 = self.values[fx + fy * self.width].into();
        let h10 = self.values[fx + 1 + fy * self.width].into();
        let h01 = self.values[fx + (fy + 1) * self.width].into();
        let h11 = self.values[fx + 1 + (fy + 1) * self.width].into();
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        Some(h0 + (h1 - h0) * (x - fx as f64))
    }

    pub fn ambient_occlusion(&self) -> Raster<u8> {
        // See: https://nothings.org/gamedev/horizon

        let mut output = Raster {
            width: self.width,
            height: self.height,
            cell_size: self.cell_size,
            xllcorner: self.xllcorner,
            yllcorner: self.yllcorner,
            values: vec![0; self.width * self.height],
        };

        let mut walk =
            |mut x: usize, mut y: usize, dx: isize, dy: isize, steps: usize, step_size: f64| {
                let mut hull = Vec::new();
                for i in 0..(steps as isize) {
                    let h: f64 = self.values[x + y * self.width].into();
                    if hull.is_empty() {
                        hull.push((-1, h));
                    }

                    while hull.len() >= 2 {
                        let (i1, h1) = hull[hull.len() - 1];
                        let (i2, h2) = hull[hull.len() - 2];
                        if ((h1 - h) * (i - i2) as f64) < ((h2 - h) * (i - i1) as f64) {
                            hull.pop();
                        } else {
                            break;
                        }
                    }

                    let (i1, h1) = hull[hull.len() - 1];
                    let slope = (h1 - h) / ((i - i1) as f64 * step_size);
                    let occlusion: f64 = 1.0 - (slope.atan() / (0.5 * PI)).max(0.0);

                    hull.push((i, h));
                    output.values[x + y * self.width] += (occlusion * 63.75) as u8;
                    x = (x as isize + dx) as usize;
                    y = (y as isize + dy) as usize;
                }
            };

        for x in 0..self.width {
            let spacing = self.horizontal_spacing(x);
            walk(x, 0, 0, 1, self.height, spacing);
            walk(x, self.height - 1, 0, -1, self.height, spacing);
        }
        for y in 0..self.height {
            let spacing = self.vertical_spacing();
            walk(0, y, 1, 0, self.width, spacing);
            walk(self.width - 1, y, -1, 0, self.width, spacing);
        }

        output
    }
}

pub(crate) trait RasterSource {
    type Type: Into<f64> + Copy;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<Self::Type>>;
}

#[allow(unused)]
pub(crate) struct AmbientOcclusionSource<T: Into<f64> + Copy + 'static>(
    pub(crate) Rc<RefCell<RasterCache<T>>>,
);
impl<T: Into<f64> + Copy + 'static> RasterSource for AmbientOcclusionSource<T> {
    type Type = u8;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<u8>> {
        self.0
            .borrow_mut()
            .get(context, latitude, longitude)
            .map(|raster| raster.ambient_occlusion())
    }
}

#[derive(Copy, Clone)]
pub(crate) enum Axis {
    X,
    Y,
}
pub(crate) struct BlurredSource {
    cache: Rc<RefCell<RasterCache<u8>>>,
    sigma: f64,
    axis: Axis,
}
impl BlurredSource {
    pub fn new(cache: Rc<RefCell<RasterCache<u8>>>, sigma: f64) -> Self {
        Self {
            cache: Rc::new(RefCell::new(RasterCache::new(
                Box::new(Self {
                    cache,
                    axis: Axis::X,
                    sigma,
                }),
                512,
            ))),
            axis: Axis::Y,
            sigma,
        }
    }
}
impl RasterSource for BlurredSource {
    type Type = u8;
    fn load(
        &self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<Raster<u8>> {
        let mut values = Vec::new();

        let guassian = |x: f64| f64::exp(-0.5 * x * x);

        let mut cache = self.cache.borrow_mut();

        let (inner0, inner, inner2) = match self.axis {
            Axis::X => {
                let inner0 = cache.get(context, latitude - 1, longitude).cloned();
                let inner = cache.get(context, latitude, longitude)?.clone();
                let inner2 = cache.get(context, latitude + 1, longitude).cloned();
                (inner0, inner, inner2)
            }
            Axis::Y => {
                let inner0 = cache.get(context, latitude, (longitude - 1) % 180).cloned();
                let inner = cache.get(context, latitude, longitude)?.clone();
                let inner2 = cache.get(context, latitude, (longitude + 1) % 180).cloned();
                (inner0, inner, inner2)
            }
        };

        let max_three_sigma = self.sigma * 3.0 / inner.vertical_spacing();
        if max_three_sigma < 1.0 {
            return Some(inner);
        }

        for adjacent in [&inner0, &inner2].iter() {
            if let Some(ref adjacent) = *adjacent {
                assert_eq!(adjacent.width, inner.width);
                assert_eq!(adjacent.height, inner.height);
                assert_eq!(adjacent.cell_size, inner.cell_size);
            }
        }

        let iwidth = inner.width as isize;
        let iheight = inner.height as isize;
        let step = match self.axis {
            Axis::X => 1,
            Axis::Y => iwidth,
        };
        for y in 0..iheight {
            for x in 0..iwidth {
                let mut v = 0.0;
                let mut d = 0.0;
                let spacing = match self.axis {
                    Axis::X => inner.vertical_spacing(),
                    Axis::Y => inner.horizontal_spacing(x as usize),
                };
                let three_sigma = (self.sigma * 3.0 / spacing).floor() as isize;

                let min_offset = match (inner0.as_ref(), self.axis) {
                    (Some(_), _) => -three_sigma,
                    (None, Axis::X) => -three_sigma.min(x),
                    (None, Axis::Y) => -three_sigma.min(y),
                };
                let max_offset = match (inner2.as_ref(), self.axis) {
                    (Some(_), _) => three_sigma,
                    (None, Axis::X) => three_sigma.min(iwidth - x - 1),
                    (None, Axis::Y) => three_sigma.min(iheight - y - 1),
                };

                for offset in min_offset..=max_offset {
                    let i = x + y * iwidth + offset * step;

                    let (raster, i) = if i < 0 {
                        (inner0.as_ref().unwrap(), (i + iwidth * iheight) as usize)
                    } else if i >= iwidth * iheight {
                        (inner2.as_ref().unwrap(), (i - iwidth * iheight) as usize)
                    } else {
                        (&inner, i as usize)
                    };

                    let g = guassian(offset as f64 * spacing / self.sigma);
                    v += g * raster.values[i] as f64;
                    d += g;
                }
                v /= d;
                assert!(v < 255.5);
                values.push(v as u8);
            }
        }

        Some(Raster { values, ..inner })
    }
}

pub(crate) struct RasterCache<T: Into<f64> + Copy> {
    source: Box<RasterSource<Type = T>>,
    holes: HashSet<(i16, i16)>,
    rasters: LruCache<(i16, i16), Raster<T>>,
}
impl<T: Into<f64> + Copy> RasterCache<T> {
    pub fn new(source: Box<RasterSource<Type = T>>, size: usize) -> Self {
        Self {
            source,
            holes: HashSet::new(),
            rasters: LruCache::new(size),
        }
    }
    pub fn get(
        &mut self,
        context: &mut AssetLoadContext,
        latitude: i16,
        longitude: i16,
    ) -> Option<&mut Raster<T>> {
        let key = (latitude, longitude);
        if self.holes.contains(&key) {
            return None;
        }
        if self.rasters.contains_key(&key) {
            return self.rasters.get_mut(&key);
        }
        match self.source.load(context, key.0, key.1) {
            Some(raster) => {
                self.rasters.insert(key, raster);
                return self.rasters.get_mut(&key);
            }
            None => {
                self.holes.insert(key);
                None
            }
        }
    }
    pub fn interpolate(
        &mut self,
        context: &mut AssetLoadContext,
        latitude: f64,
        longitude: f64,
    ) -> Option<f64> {
        self.get(context, latitude.floor() as i16, longitude.floor() as i16)
            .and_then(|raster| raster.interpolate(latitude, longitude))
    }
}

/// Currently assumes that values are taken at the *center* of cells.
pub(crate) struct GlobalRaster<T: Into<f64> + Copy, C: Index<usize, Output = T> = Vec<T>> {
    pub width: usize,
    pub height: usize,
    pub bands: usize,
    pub values: C,
}
impl<T: Into<f64> + Copy, C: Index<usize, Output = T>> GlobalRaster<T, C> {
    /// Returns the approximate grid spacing in meters.
    pub fn spacing(&self) -> f64 {
        let sx = 2.0 * PI * coordinates::PLANET_RADIUS / self.width as f64;
        let sy = PI * coordinates::PLANET_RADIUS / self.height as f64;
        sx.min(sy)
    }

    fn get(&self, x: i64, y: i64, band: usize) -> f64 {
        let y = y.max(0).min(self.height as i64) as usize;
        let x = (((x % self.width as i64) + self.width as i64) % self.width as i64) as usize;
        self.values[(x + y * self.width) * self.bands + band].into()
    }

    pub fn interpolate(&self, latitude: f64, longitude: f64, band: usize) -> f64 {
        assert!(latitude >= -90.0 && latitude <= 90.0);

        let x = (longitude + 180.0) / 360.0 * self.width as f64 - 0.5;
        let y = (90.0 - latitude) / 180.0 * self.height as f64 - 0.5;

        let fx = x.floor() as i64;
        let fy = y.floor() as i64;

        let h00 = self.get(fx, fy, band);
        let h10 = self.get(fx + 1, fy, band);
        let h01 = self.get(fx, fy + 1, band);
        let h11 = self.get(fx + 1, fy + 1, band);
        let h0 = h00 + (h01 - h00) * (y - fy as f64);
        let h1 = h10 + (h11 - h10) * (y - fy as f64);
        h0 + (h1 - h0) * (x - fx as f64)
    }
}
<|endoftext|>


<commit_before>use crate::{
    frame::Frame,
    packer::{Packer, SkylinePacker},
    rect::Rect,
    texture::{Pixel, SubTexture, Texture},
    texture_packer_config::TexturePackerConfig,
};
use std::collections::HashMap;
use std::cmp::min;
use std::hash::Hash;

pub type PackResult<T> = Result<T, PackError>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PackError {
    TextureTooLargeToFitIntoAtlas,
}

/// Packs textures into a single texture atlas.
pub struct TexturePacker<'a, T: 'a + Clone, K: Clone + Eq + Hash> {
    textures: HashMap<K, SubTexture<'a, T>>,
    frames: HashMap<K, Frame<K>>,
    packer: Box<dyn Packer<K>>,
    config: TexturePackerConfig,
}

impl<'a, Pix: Pixel, T: 'a + Clone + Texture<Pixel = Pix>, K: Clone + Eq + Hash> TexturePacker<'a, T, K> {
    /// Create a new packer using the skyline packing algorithm.
    pub fn new_skyline(config: TexturePackerConfig) -> Self {
        TexturePacker {
            textures: HashMap::new(),
            frames: HashMap::new(),
            packer: Box::new(SkylinePacker::new(config)),
            config,
        }
    }
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>, K: Clone + Eq + Hash> TexturePacker<'a, T, K> {
    /// Check if the texture can be packed into this packer.
    pub fn can_pack(&self, texture: &'a T) -> bool {
        let rect = texture.into();
        self.packer.can_pack(&rect)
    }

    /// Pack the `texture` into this packer, taking a reference of the texture object.
    pub fn pack_ref(&mut self, key: K, texture: &'a T) -> PackResult<()> {
        let rect = texture.into();
        if !self.packer.can_pack(&rect) {
            return Err(PackError::TextureTooLargeToFitIntoAtlas);
        }

        let (w, h) = (texture.width(), texture.height());
        let source = if self.config.trim {
            trim_texture(texture)
        } else {
            Rect::new(0, 0, w, h)
        };

        let texture = SubTexture::from_ref(texture, source);
        let rect = (&texture).into();
        if let Some(mut frame) = self.packer.pack(key.clone(), &rect) {
            frame.frame.x += self.config.border_padding;
            frame.frame.y += self.config.border_padding;
            frame.trimmed = self.config.trim;
            frame.source = source;
            frame.source.w = w;
            frame.source.h = h;
            self.frames.insert(key.clone(), frame);
        }

        self.textures.insert(key, texture);
        Ok(())
    }

    /// Pack the `texture` into this packer, taking ownership of the texture object.
    pub fn pack_own(&mut self, key: K, texture: T) -> PackResult<()> {
        let rect = (&texture).into();
        if !self.packer.can_pack(&rect) {
            return Err(PackError::TextureTooLargeToFitIntoAtlas);
        }

        let (w, h) = (texture.width(), texture.height());
        let source = if self.config.trim {
            trim_texture(&texture)
        } else {
            Rect::new(0, 0, w, h)
        };

        let texture = SubTexture::new(texture, source);
        let rect = (&texture).into();
        if let Some(mut frame) = self.packer.pack(key.clone(), &rect) {
            frame.frame.x += self.config.border_padding;
            frame.frame.y += self.config.border_padding;
            frame.trimmed = self.config.trim;
            frame.source = source;
            frame.source.w = w;
            frame.source.h = h;
            self.frames.insert(key.clone(), frame);
        }

        self.textures.insert(key, texture);
        Ok(())
    }

    /// Get the backing mapping from strings to frames.
    pub fn get_frames(&self) -> &HashMap<K, Frame<K>> {
        &self.frames
    }

    /// Acquire a frame by its name.
    pub fn get_frame(&self, key: &K) -> Option<&Frame<K>> {
        if let Some(frame) = self.frames.get(key) {
            Some(frame)
        } else {
            None
        }
    }

    /// Get the frame that overlaps with a specified coordinate.
    fn get_frame_at(&self, x: u32, y: u32) -> Option<&Frame<K>> {
        let extrusion = self.config.texture_extrusion;

        for (_, frame) in self.frames.iter() {
            let mut rect = frame.frame;

            rect.x = rect.x.saturating_sub(extrusion);
            rect.y = rect.y.saturating_sub(extrusion);

            rect.w += extrusion * 2;
            rect.h += extrusion * 2;

            if rect.contains_point(x, y) {
                return Some(frame);
            }
        }
        None
    }
}

impl<'a, Pix, T: Clone, K: Clone + Eq + Hash> Texture for TexturePacker<'a, T, K>
where
    Pix: Pixel,
    T: Texture<Pixel = Pix>,
{
    type Pixel = Pix;

    fn width(&self) -> u32 {
        let mut right = None;

        for (_, frame) in self.frames.iter() {
            if let Some(r) = right {
                if frame.frame.right() > r {
                    right = Some(frame.frame.right());
                }
            } else {
                right = Some(frame.frame.right());
            }
        }

        if let Some(right) = right {
            right + 1 + self.config.border_padding
        } else {
            0
        }
    }

    fn height(&self) -> u32 {
        let mut bottom = None;

        for (_, frame) in self.frames.iter() {
            if let Some(b) = bottom {
                if frame.frame.bottom() > b {
                    bottom = Some(frame.frame.bottom());
                }
            } else {
                bottom = Some(frame.frame.bottom());
            }
        }

        if let Some(bottom) = bottom {
            bottom + 1 + self.config.border_padding
        } else {
            0
        }
    }

    fn get(&self, x: u32, y: u32) -> Option<Pix> {
        if let Some(frame) = self.get_frame_at(x, y) {
            if self.config.texture_outlines && frame.frame.is_outline(x, y) {
                return Some(<Pix as Pixel>::outline());
            }

            if let Some(texture) = self.textures.get(&frame.key) {
                let x = x.saturating_sub(frame.frame.x);
                let y = y.saturating_sub(frame.frame.y);

                let x = min(x, texture.width() - 1);
                let y = min(y, texture.height() - 1);

                return if frame.rotated {
                    texture.get_rotated(x, y)
                } else {
                    texture.get(x, y)
                };
            }
        }

        None
    }

    fn set(&mut self, _x: u32, _y: u32, _val: Pix) {
        panic!("Can't set pixel directly");
    }
}

fn trim_texture<T: Texture>(texture: &T) -> Rect {
    let mut x1 = 0;
    for x in 0..texture.width() {
        if texture.is_column_transparent(x) {
            x1 = x + 1;
        } else {
            break;
        }
    }

    let mut x2 = texture.width() - 1;
    for x in 0..texture.width() {
        let x = texture.width() - x - 1;
        if texture.is_column_transparent(x) {
            x2 = x - 1;
        } else {
            break;
        }
    }

    let mut y1 = 0;
    for y in 0..texture.height() {
        if texture.is_row_transparent(y) {
            y1 = y + 1;
        } else {
            break;
        }
    }

    let mut y2 = texture.height() - 1;
    for y in 0..texture.height() {
        let y = texture.height() - y - 1;
        if texture.is_row_transparent(y) {
            y2 = y - 1;
        } else {
            break;
        }
    }
    Rect::new_with_points(x1, y1, x2, y2)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::texture::memory_rgba8_texture::MemoryRGBA8Texture;

    #[test]
    fn able_to_store_in_struct() {
        let packer = TexturePacker::new_skyline(TexturePackerConfig::default());

        struct MyPacker<'a> {
            _packer: TexturePacker<'a, MemoryRGBA8Texture, String>,
        }

        MyPacker { _packer: packer };
    }
}
<commit_msg>Fix for: https://github.com/PistonDevelopers/texture_packer/issues/74<commit_after>use crate::{
    frame::Frame,
    packer::{Packer, SkylinePacker},
    rect::Rect,
    texture::{Pixel, SubTexture, Texture},
    texture_packer_config::TexturePackerConfig,
};
use std::collections::HashMap;
use std::cmp::min;
use std::hash::Hash;

pub type PackResult<T> = Result<T, PackError>;

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum PackError {
    TextureTooLargeToFitIntoAtlas,
}

/// Packs textures into a single texture atlas.
pub struct TexturePacker<'a, T: 'a + Clone, K: Clone + Eq + Hash> {
    textures: HashMap<K, SubTexture<'a, T>>,
    frames: HashMap<K, Frame<K>>,
    packer: Box<dyn Packer<K>>,
    config: TexturePackerConfig,
}

impl<'a, Pix: Pixel, T: 'a + Clone + Texture<Pixel = Pix>, K: Clone + Eq + Hash> TexturePacker<'a, T, K> {
    /// Create a new packer using the skyline packing algorithm.
    pub fn new_skyline(config: TexturePackerConfig) -> Self {
        TexturePacker {
            textures: HashMap::new(),
            frames: HashMap::new(),
            packer: Box::new(SkylinePacker::new(config)),
            config,
        }
    }
}

impl<'a, Pix: Pixel, T: Clone + Texture<Pixel = Pix>, K: Clone + Eq + Hash> TexturePacker<'a, T, K> {
    /// Check if the texture can be packed into this packer.
    pub fn can_pack(&self, texture: &'a T) -> bool {
        let rect = texture.into();
        self.packer.can_pack(&rect)
    }

    /// Pack the `texture` into this packer, taking a reference of the texture object.
    pub fn pack_ref(&mut self, key: K, texture: &'a T) -> PackResult<()> {
        let rect = texture.into();
        if !self.packer.can_pack(&rect) {
            return Err(PackError::TextureTooLargeToFitIntoAtlas);
        }

        let (w, h) = (texture.width(), texture.height());
        let source = if self.config.trim {
            trim_texture(texture)
        } else {
            Rect::new(0, 0, w, h)
        };

        let texture = SubTexture::from_ref(texture, source);
        let rect = (&texture).into();
        if let Some(mut frame) = self.packer.pack(key.clone(), &rect) {
            frame.frame.x += self.config.border_padding;
            frame.frame.y += self.config.border_padding;
            frame.trimmed = self.config.trim;
            frame.source = source;
            frame.source.w = w;
            frame.source.h = h;
            self.frames.insert(key.clone(), frame);
        }

        self.textures.insert(key, texture);
        Ok(())
    }

    /// Pack the `texture` into this packer, taking ownership of the texture object.
    pub fn pack_own(&mut self, key: K, texture: T) -> PackResult<()> {
        let rect = (&texture).into();
        if !self.packer.can_pack(&rect) {
            return Err(PackError::TextureTooLargeToFitIntoAtlas);
        }

        let (w, h) = (texture.width(), texture.height());
        let source = if self.config.trim {
            trim_texture(&texture)
        } else {
            Rect::new(0, 0, w, h)
        };

        let texture = SubTexture::new(texture, source);
        let rect = (&texture).into();
        if let Some(mut frame) = self.packer.pack(key.clone(), &rect) {
            frame.frame.x += self.config.border_padding;
            frame.frame.y += self.config.border_padding;
            frame.trimmed = self.config.trim;
            frame.source = source;
            frame.source.w = w;
            frame.source.h = h;
            self.frames.insert(key.clone(), frame);
        }

        self.textures.insert(key, texture);
        Ok(())
    }

    /// Get the backing mapping from strings to frames.
    pub fn get_frames(&self) -> &HashMap<K, Frame<K>> {
        &self.frames
    }

    /// Acquire a frame by its name.
    pub fn get_frame(&self, key: &K) -> Option<&Frame<K>> {
        if let Some(frame) = self.frames.get(key) {
            Some(frame)
        } else {
            None
        }
    }

    /// Get the frame that overlaps with a specified coordinate.
    fn get_frame_at(&self, x: u32, y: u32) -> Option<&Frame<K>> {
        let extrusion = self.config.texture_extrusion;

        for (_, frame) in self.frames.iter() {
            let mut rect = frame.frame;

            rect.x = rect.x.saturating_sub(extrusion);
            rect.y = rect.y.saturating_sub(extrusion);

            rect.w += extrusion * 2;
            rect.h += extrusion * 2;

            if rect.contains_point(x, y) {
                return Some(frame);
            }
        }
        None
    }
}

impl<'a, Pix, T: Clone, K: Clone + Eq + Hash> Texture for TexturePacker<'a, T, K>
where
    Pix: Pixel,
    T: Texture<Pixel = Pix>,
{
    type Pixel = Pix;

    fn width(&self) -> u32 {
        let mut right = None;

        for (_, frame) in self.frames.iter() {
            if let Some(r) = right {
                if frame.frame.right() > r {
                    right = Some(frame.frame.right());
                }
            } else {
                right = Some(frame.frame.right());
            }
        }

        if let Some(right) = right {
            right + 1 + self.config.border_padding
        } else {
            0
        }
    }

    fn height(&self) -> u32 {
        let mut bottom = None;

        for (_, frame) in self.frames.iter() {
            if let Some(b) = bottom {
                if frame.frame.bottom() > b {
                    bottom = Some(frame.frame.bottom());
                }
            } else {
                bottom = Some(frame.frame.bottom());
            }
        }

        if let Some(bottom) = bottom {
            bottom + 1 + self.config.border_padding
        } else {
            0
        }
    }

    fn get(&self, x: u32, y: u32) -> Option<Pix> {
        if let Some(frame) = self.get_frame_at(x, y) {
            if self.config.texture_outlines && frame.frame.is_outline(x, y) {
                return Some(<Pix as Pixel>::outline());
            }

            if let Some(texture) = self.textures.get(&frame.key) {
                let x = x.saturating_sub(frame.frame.x);
                let y = y.saturating_sub(frame.frame.y);

                return if frame.rotated {
                    let x = min(x, texture.height() - 1);
                    let y = min(y, texture.width() - 1);
                    texture.get_rotated(x, y)
                } else {
                    let x = min(x, texture.width() - 1);
                    let y = min(y, texture.height() - 1);
                    texture.get(x, y)
                };
            }
        }

        None
    }

    fn set(&mut self, _x: u32, _y: u32, _val: Pix) {
        panic!("Can't set pixel directly");
    }
}

fn trim_texture<T: Texture>(texture: &T) -> Rect {
    let mut x1 = 0;
    for x in 0..texture.width() {
        if texture.is_column_transparent(x) {
            x1 = x + 1;
        } else {
            break;
        }
    }

    let mut x2 = texture.width() - 1;
    for x in 0..texture.width() {
        let x = texture.width() - x - 1;
        if texture.is_column_transparent(x) {
            x2 = x - 1;
        } else {
            break;
        }
    }

    let mut y1 = 0;
    for y in 0..texture.height() {
        if texture.is_row_transparent(y) {
            y1 = y + 1;
        } else {
            break;
        }
    }

    let mut y2 = texture.height() - 1;
    for y in 0..texture.height() {
        let y = texture.height() - y - 1;
        if texture.is_row_transparent(y) {
            y2 = y - 1;
        } else {
            break;
        }
    }
    Rect::new_with_points(x1, y1, x2, y2)
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::texture::memory_rgba8_texture::MemoryRGBA8Texture;

    #[test]
    fn able_to_store_in_struct() {
        let packer = TexturePacker::new_skyline(TexturePackerConfig::default());

        struct MyPacker<'a> {
            _packer: TexturePacker<'a, MemoryRGBA8Texture, String>,
        }

        MyPacker { _packer: packer };
    }
}
<|endoftext|>


<commit_before>use std::result::*;
use std::rc::*;

use rustc_serialize::*;

use super::treenode::*;
use super::basictree::*;
use super::values::*;

///
/// Encoder that will write to the specified tree node
///
struct TreeNodeEncoder {
    tag:    String,
    value:  TreeValue,
    child:  Option<Rc<TreeNode>>
}

impl TreeNodeEncoder {
    fn new() -> TreeNodeEncoder {
        TreeNodeEncoder {
            tag:    "".to_string(),
            value:  TreeValue::Nothing,
            child:  None }
    }

    fn to_basic_tree_node(&self) -> BasicTree {
        let new_node = BasicTree::new(&*self.tag, self.value.to_owned());

        self.child.to_owned().and_then(|child| {
            new_node.set_child_ref(child);
            Some(())
        });

        new_node
    }
}

pub enum TreeNodeCodingError {
    UnsupportedType
}

impl Encoder for TreeNodeEncoder {
    type Error = TreeNodeCodingError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        self.value = TreeValue::Nothing;
        Ok(())
    }

    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v);
        Ok(())
    }

    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.value = TreeValue::Bool(v);
        Ok(())
    }

    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v);
        Ok(())
    }

    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v as f64);
        Ok(())
    }

    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.value = TreeValue::String(v.to_string());
        Ok(())
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.value = TreeValue::String(name.to_string());

        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        // Encode the function into a new encoder
        let mut node_encoder = TreeNodeEncoder::new();
        let encoding_error = f(&mut node_encoder);

        // Short-circuit on error
        if encoding_error.is_err() {
            return encoding_error;
        }

        // Replace the child node with the node generated for the new encoder
        let new_node = node_encoder.to_basic_tree_node();

        self.child.to_owned().and_then(|sibling| {
            new_node.set_sibling_ref(sibling);
            Some(())
        });

        // Save the node we just created and update the tree
        self.child = Some(Rc::new(new_node));

        Ok(())
    }

    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }
}
<commit_msg>Name change<commit_after>use std::result::*;
use std::rc::*;

use rustc_serialize::*;

use super::treenode::*;
use super::basictree::*;
use super::values::*;

///
/// Encoder that will write to the specified tree node
///
struct TreeNodeEncoder {
    tag:    String,
    value:  TreeValue,
    child:  Option<Rc<TreeNode>>
}

impl TreeNodeEncoder {
    fn new() -> TreeNodeEncoder {
        TreeNodeEncoder {
            tag:    "".to_string(),
            value:  TreeValue::Nothing,
            child:  None }
    }

    fn to_basic_tree_node(&self) -> BasicTree {
        let new_node = BasicTree::new(&*self.tag, self.value.to_owned());

        self.child.to_owned().and_then(|child| {
            new_node.set_child_ref(child);
            Some(())
        });

        new_node
    }
}

pub enum TreeNodeCodingError {
    UnsupportedType
}

impl Encoder for TreeNodeEncoder {
    type Error = TreeNodeCodingError;

    fn emit_nil(&mut self) -> Result<(), Self::Error> {
        self.value = TreeValue::Nothing;
        Ok(())
    }

    fn emit_i32(&mut self, v: i32) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v);
        Ok(())
    }

    fn emit_i16(&mut self, v: i16) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_i8(&mut self, v: i8) -> Result<(), Self::Error> {
        self.value = TreeValue::Int(v as i32);
        Ok(())
    }

    fn emit_bool(&mut self, v: bool) -> Result<(), Self::Error> {
        self.value = TreeValue::Bool(v);
        Ok(())
    }

    fn emit_f64(&mut self, v: f64) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v);
        Ok(())
    }

    fn emit_f32(&mut self, v: f32) -> Result<(), Self::Error> {
        self.value = TreeValue::Real(v as f64);
        Ok(())
    }

    fn emit_str(&mut self, v: &str) -> Result<(), Self::Error> {
        self.value = TreeValue::String(v.to_string());
        Ok(())
    }

    fn emit_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        self.value = TreeValue::String(name.to_string());

        f(self)
    }

    fn emit_struct_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        // Encode the function into a new encoder
        let mut node_encoder = TreeNodeEncoder::new();
        let encoding_result = f(&mut node_encoder);

        // Short-circuit on error
        if encoding_result.is_err() {
            return encoding_result;
        }

        // Replace the child node with the node generated for the new encoder
        let new_node = node_encoder.to_basic_tree_node();

        self.child.to_owned().and_then(|sibling| {
            new_node.set_sibling_ref(sibling);
            Some(())
        });

        // Save the node we just created and update the tree
        self.child = Some(Rc::new(new_node));

        Ok(())
    }

    fn emit_usize(&mut self, v: usize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u64(&mut self, v: u64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u32(&mut self, v: u32) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u16(&mut self, v: u16) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_u8(&mut self, v: u8) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_isize(&mut self, v: isize) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_i64(&mut self, v: i64) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_char(&mut self, v: char) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum<F>(&mut self, name: &str, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_variant_arg<F>(&mut self, a_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant<F>(&mut self, v_name: &str, v_id: usize, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_enum_struct_variant_field<F>(&mut self, f_name: &str, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_arg<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct<F>(&mut self, name: &str, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_tuple_struct_arg<F>(&mut self, f_idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_none(&mut self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_option_some<F>(&mut self, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_seq_elt<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map<F>(&mut self, len: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_key<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }

    fn emit_map_elt_val<F>(&mut self, idx: usize, f: F) -> Result<(), Self::Error> where F: FnOnce(&mut Self) -> Result<(), Self::Error> {
        Err(TreeNodeCodingError::UnsupportedType)
    }
}
<|endoftext|>