<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 crate::bindgen::config::Profile;
use std::env;
use std::error;
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::{from_utf8, Utf8Error};

extern crate tempfile;
use self::tempfile::Builder;

#[derive(Debug)]
/// Possible errors that can occur during `rustc -Zunpretty=expanded`.
pub enum Error {
    /// Error during creation of temporary directory
    Io(io::Error),
    /// Output of `cargo metadata` was not valid utf8
    Utf8(Utf8Error),
    /// Error during execution of `cargo rustc -Zunpretty=expanded`
    Compile(String),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}
impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Self {
        Error::Utf8(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Io(ref err) => err.fmt(f),
            Error::Utf8(ref err) => err.fmt(f),
            Error::Compile(ref err) => write!(f, "{}", err),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            Error::Io(ref err) => Some(err),
            Error::Utf8(ref err) => Some(err),
            Error::Compile(..) => None,
        }
    }
}

/// Use rustc to expand and pretty print the crate into a single file,
/// removing any macros in the process.
#[allow(clippy::too_many_arguments)]
pub fn expand(
    manifest_path: &Path,
    crate_name: &str,
    version: Option<&str>,
    use_tempdir: bool,
    expand_all_features: bool,
    expand_default_features: bool,
    expand_features: &Option<Vec<String>>,
    profile: Profile,
) -> Result<String, Error> {
    let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
    let mut cmd = Command::new(cargo);

    let mut _temp_dir = None; // drop guard
    if use_tempdir {
        _temp_dir = Some(Builder::new().prefix("cbindgen-expand").tempdir()?);
        cmd.env("CARGO_TARGET_DIR", _temp_dir.unwrap().path());
    } else if let Ok(ref path) = env::var("CARGO_EXPAND_TARGET_DIR") {
        cmd.env("CARGO_TARGET_DIR", path);
    } else if let Ok(ref path) = env::var("OUT_DIR") {
        // When cbindgen was started programatically from a build.rs file, Cargo is running and
        // locking the default target directory. In this case we need to use another directory,
        // else we would end up in a deadlock. If Cargo is running `OUT_DIR` will be set, so we
        // can use a directory relative to that.
        cmd.env("CARGO_TARGET_DIR", PathBuf::from(path).join("expanded"));
    }

    // Set this variable so that we don't call it recursively if we expand a crate that is using
    // cbindgen
    cmd.env("_CBINDGEN_IS_RUNNING", "1");

    cmd.arg("rustc");
    cmd.arg("--lib");
    cmd.arg("--profile=check");
    cmd.arg("--manifest-path");
    cmd.arg(manifest_path);
    if let Some(features) = expand_features {
        cmd.arg("--features");
        let mut features_str = String::new();
        for (index, feature) in features.iter().enumerate() {
            if index != 0 {
                features_str.push(' ');
            }
            features_str.push_str(feature);
        }
        cmd.arg(features_str);
    }
    if expand_all_features {
        cmd.arg("--all-features");
    }
    if !expand_default_features {
        cmd.arg("--no-default-features");
    }
    match profile {
        Profile::Debug => {}
        Profile::Release => {
            cmd.arg("--release");
        }
    }
    cmd.arg("-p");
    let mut package = crate_name.to_owned();
    if let Some(version) = version {
        package.push(':');
        package.push_str(version);
    }
    cmd.arg(&package);
    cmd.arg("--verbose");
    cmd.arg("--");
    cmd.arg("-Zunpretty=expanded");
    info!("Command: {:?}", cmd);
    let output = cmd.output()?;

    let src = from_utf8(&output.stdout)?.to_owned();
    let error = from_utf8(&output.stderr)?.to_owned();

    if src.is_empty() {
        Err(Error::Compile(error))
    } else {
        Ok(src)
    }
}
<commit_msg>Don't use `check` profile when expanding code on a release build<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 crate::bindgen::config::Profile;
use std::env;
use std::error;
use std::fmt;
use std::io;
use std::path::{Path, PathBuf};
use std::process::Command;
use std::str::{from_utf8, Utf8Error};

extern crate tempfile;
use self::tempfile::Builder;

#[derive(Debug)]
/// Possible errors that can occur during `rustc -Zunpretty=expanded`.
pub enum Error {
    /// Error during creation of temporary directory
    Io(io::Error),
    /// Output of `cargo metadata` was not valid utf8
    Utf8(Utf8Error),
    /// Error during execution of `cargo rustc -Zunpretty=expanded`
    Compile(String),
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Self {
        Error::Io(err)
    }
}
impl From<Utf8Error> for Error {
    fn from(err: Utf8Error) -> Self {
        Error::Utf8(err)
    }
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            Error::Io(ref err) => err.fmt(f),
            Error::Utf8(ref err) => err.fmt(f),
            Error::Compile(ref err) => write!(f, "{}", err),
        }
    }
}

impl error::Error for Error {
    fn source(&self) -> Option<&(dyn error::Error + 'static)> {
        match self {
            Error::Io(ref err) => Some(err),
            Error::Utf8(ref err) => Some(err),
            Error::Compile(..) => None,
        }
    }
}

/// Use rustc to expand and pretty print the crate into a single file,
/// removing any macros in the process.
#[allow(clippy::too_many_arguments)]
pub fn expand(
    manifest_path: &Path,
    crate_name: &str,
    version: Option<&str>,
    use_tempdir: bool,
    expand_all_features: bool,
    expand_default_features: bool,
    expand_features: &Option<Vec<String>>,
    profile: Profile,
) -> Result<String, Error> {
    let cargo = env::var("CARGO").unwrap_or_else(|_| String::from("cargo"));
    let mut cmd = Command::new(cargo);

    let mut _temp_dir = None; // drop guard
    if use_tempdir {
        _temp_dir = Some(Builder::new().prefix("cbindgen-expand").tempdir()?);
        cmd.env("CARGO_TARGET_DIR", _temp_dir.unwrap().path());
    } else if let Ok(ref path) = env::var("CARGO_EXPAND_TARGET_DIR") {
        cmd.env("CARGO_TARGET_DIR", path);
    } else if let Ok(ref path) = env::var("OUT_DIR") {
        // When cbindgen was started programatically from a build.rs file, Cargo is running and
        // locking the default target directory. In this case we need to use another directory,
        // else we would end up in a deadlock. If Cargo is running `OUT_DIR` will be set, so we
        // can use a directory relative to that.
        cmd.env("CARGO_TARGET_DIR", PathBuf::from(path).join("expanded"));
    }

    // Set this variable so that we don't call it recursively if we expand a crate that is using
    // cbindgen
    cmd.env("_CBINDGEN_IS_RUNNING", "1");

    cmd.arg("rustc");
    cmd.arg("--lib");
    // When build with the release profile we can't choose the `check` profile.
    if profile != Profile::Release {
        cmd.arg("--profile=check");
    }
    cmd.arg("--manifest-path");
    cmd.arg(manifest_path);
    if let Some(features) = expand_features {
        cmd.arg("--features");
        let mut features_str = String::new();
        for (index, feature) in features.iter().enumerate() {
            if index != 0 {
                features_str.push(' ');
            }
            features_str.push_str(feature);
        }
        cmd.arg(features_str);
    }
    if expand_all_features {
        cmd.arg("--all-features");
    }
    if !expand_default_features {
        cmd.arg("--no-default-features");
    }
    match profile {
        Profile::Debug => {}
        Profile::Release => {
            cmd.arg("--release");
        }
    }
    cmd.arg("-p");
    let mut package = crate_name.to_owned();
    if let Some(version) = version {
        package.push(':');
        package.push_str(version);
    }
    cmd.arg(&package);
    cmd.arg("--verbose");
    cmd.arg("--");
    cmd.arg("-Zunpretty=expanded");
    info!("Command: {:?}", cmd);
    let output = cmd.output()?;

    let src = from_utf8(&output.stdout)?.to_owned();
    let error = from_utf8(&output.stderr)?.to_owned();

    if src.is_empty() {
        Err(Error::Compile(error))
    } else {
        Ok(src)
    }
}
<|endoftext|>


<commit_before>use std::fmt::Display;
use thiserror::Error;

#[derive(Error, Debug)]
#[error("braced error: {msg}")]
struct BracedError {
    msg: String,
}

#[derive(Error, Debug)]
#[error("braced error")]
struct BracedUnused {
    extra: usize,
}

#[derive(Error, Debug)]
#[error("tuple error: {0}")]
struct TupleError(usize);

#[derive(Error, Debug)]
#[error("unit error")]
struct UnitError;

#[derive(Error, Debug)]
enum EnumError {
    #[error("braced error: {id}")]
    Braced { id: usize, },
    #[error("tuple error: {0}")]
    Tuple(usize),
    #[error("unit error")]
    Unit,
}

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_display() {
    assert(
        "braced error: T",
        BracedError {
            msg: "T".to_owned(),
        },
    );
    assert("braced error", BracedUnused { extra: 0 });
    assert("tuple error: 0", TupleError(0));
    assert("unit error", UnitError);
    assert("braced error: 0", EnumError::Braced { id: 0 });
    assert("tuple error: 0", EnumError::Tuple(0));
    assert("unit error", EnumError::Unit);
}
<commit_msg>Add test of an interpolated expression<commit_after>use std::fmt::Display;
use thiserror::Error;

#[derive(Error, Debug)]
#[error("braced error: {msg}")]
struct BracedError {
    msg: String,
}

#[derive(Error, Debug)]
#[error("braced error")]
struct BracedUnused {
    extra: usize,
}

#[derive(Error, Debug)]
#[error("tuple error: {0}")]
struct TupleError(usize);

#[derive(Error, Debug)]
#[error("unit error")]
struct UnitError;

#[derive(Error, Debug)]
enum EnumError {
    #[error("braced error: {id}")]
    Braced { id: usize, },
    #[error("tuple error: {0}")]
    Tuple(usize),
    #[error("unit error")]
    Unit,
}

#[derive(Error, Debug)]
#[error("1 + 1 = {}", 1 + 1)]
struct Arithmetic;

fn assert<T: Display>(expected: &str, value: T) {
    assert_eq!(expected, value.to_string());
}

#[test]
fn test_display() {
    assert(
        "braced error: T",
        BracedError {
            msg: "T".to_owned(),
        },
    );
    assert("braced error", BracedUnused { extra: 0 });
    assert("tuple error: 0", TupleError(0));
    assert("unit error", UnitError);
    assert("braced error: 0", EnumError::Braced { id: 0 });
    assert("tuple error: 0", EnumError::Tuple(0));
    assert("unit error", EnumError::Unit);
    assert("1 + 1 = 2", Arithmetic);
}
<|endoftext|>


<commit_before>#![allow(
    // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
    clippy::nonstandard_macro_braces,
)]

mod drop;

use crate::drop::{DetectDrop, Flag};
use anyhow::{Context, Error, Result};
use std::fmt::{self, Display};
use thiserror::Error;

// https://github.com/dtolnay/anyhow/issues/18
#[test]
fn test_inference() -> Result<()> {
    let x = "1";
    let y: u32 = x.parse().context("...")?;
    assert_eq!(y, 1);
    Ok(())
}

macro_rules! context_type {
    ($name:ident) => {
        #[derive(Debug)]
        struct $name {
            message: &'static str,
            drop: DetectDrop,
        }

        impl Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(self.message)
            }
        }
    };
}

context_type!(HighLevel);
context_type!(MidLevel);

#[derive(Error, Debug)]
#[error("{message}")]
struct LowLevel {
    message: &'static str,
    drop: DetectDrop,
}

struct Dropped {
    low: Flag,
    mid: Flag,
    high: Flag,
}

impl Dropped {
    fn none(&self) -> bool {
        !self.low.get() && !self.mid.get() && !self.high.get()
    }

    fn all(&self) -> bool {
        self.low.get() && self.mid.get() && self.high.get()
    }
}

fn make_chain() -> (Error, Dropped) {
    let dropped = Dropped {
        low: Flag::new(),
        mid: Flag::new(),
        high: Flag::new(),
    };

    let low = LowLevel {
        message: "no such file or directory",
        drop: DetectDrop::new(&dropped.low),
    };

    // impl Context for Result<T, E>
    let mid = Err::<(), LowLevel>(low)
        .context(MidLevel {
            message: "failed to load config",
            drop: DetectDrop::new(&dropped.mid),
        })
        .unwrap_err();

    // impl Context for Result<T, Error>
    let high = Err::<(), Error>(mid)
        .context(HighLevel {
            message: "failed to start server",
            drop: DetectDrop::new(&dropped.high),
        })
        .unwrap_err();

    (high, dropped)
}

#[test]
fn test_downcast_ref() {
    let (err, dropped) = make_chain();

    assert!(!err.is::<String>());
    assert!(err.downcast_ref::<String>().is_none());

    assert!(err.is::<HighLevel>());
    let high = err.downcast_ref::<HighLevel>().unwrap();
    assert_eq!(high.to_string(), "failed to start server");

    assert!(err.is::<MidLevel>());
    let mid = err.downcast_ref::<MidLevel>().unwrap();
    assert_eq!(mid.to_string(), "failed to load config");

    assert!(err.is::<LowLevel>());
    let low = err.downcast_ref::<LowLevel>().unwrap();
    assert_eq!(low.to_string(), "no such file or directory");

    assert!(dropped.none());
    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_high() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<HighLevel>().unwrap();
    assert!(!dropped.high.get());
    assert!(dropped.low.get() && dropped.mid.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_mid() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<MidLevel>().unwrap();
    assert!(!dropped.mid.get());
    assert!(dropped.low.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_low() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<LowLevel>().unwrap();
    assert!(!dropped.low.get());
    assert!(dropped.mid.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_unsuccessful_downcast() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<String>().unwrap_err();
    assert!(dropped.none());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_root_cause() {
    let (err, _) = make_chain();

    assert_eq!(err.root_cause().to_string(), "no such file or directory");
}
<commit_msg>Clean up unused field warning in test suite<commit_after>#![allow(
    // Clippy bug: https://github.com/rust-lang/rust-clippy/issues/7422
    clippy::nonstandard_macro_braces,
)]

mod drop;

use crate::drop::{DetectDrop, Flag};
use anyhow::{Context, Error, Result};
use std::fmt::{self, Display};
use thiserror::Error;

// https://github.com/dtolnay/anyhow/issues/18
#[test]
fn test_inference() -> Result<()> {
    let x = "1";
    let y: u32 = x.parse().context("...")?;
    assert_eq!(y, 1);
    Ok(())
}

macro_rules! context_type {
    ($name:ident) => {
        #[derive(Debug)]
        struct $name {
            message: &'static str,
            #[allow(dead_code)]
            drop: DetectDrop,
        }

        impl Display for $name {
            fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
                f.write_str(self.message)
            }
        }
    };
}

context_type!(HighLevel);
context_type!(MidLevel);

#[derive(Error, Debug)]
#[error("{message}")]
struct LowLevel {
    message: &'static str,
    drop: DetectDrop,
}

struct Dropped {
    low: Flag,
    mid: Flag,
    high: Flag,
}

impl Dropped {
    fn none(&self) -> bool {
        !self.low.get() && !self.mid.get() && !self.high.get()
    }

    fn all(&self) -> bool {
        self.low.get() && self.mid.get() && self.high.get()
    }
}

fn make_chain() -> (Error, Dropped) {
    let dropped = Dropped {
        low: Flag::new(),
        mid: Flag::new(),
        high: Flag::new(),
    };

    let low = LowLevel {
        message: "no such file or directory",
        drop: DetectDrop::new(&dropped.low),
    };

    // impl Context for Result<T, E>
    let mid = Err::<(), LowLevel>(low)
        .context(MidLevel {
            message: "failed to load config",
            drop: DetectDrop::new(&dropped.mid),
        })
        .unwrap_err();

    // impl Context for Result<T, Error>
    let high = Err::<(), Error>(mid)
        .context(HighLevel {
            message: "failed to start server",
            drop: DetectDrop::new(&dropped.high),
        })
        .unwrap_err();

    (high, dropped)
}

#[test]
fn test_downcast_ref() {
    let (err, dropped) = make_chain();

    assert!(!err.is::<String>());
    assert!(err.downcast_ref::<String>().is_none());

    assert!(err.is::<HighLevel>());
    let high = err.downcast_ref::<HighLevel>().unwrap();
    assert_eq!(high.to_string(), "failed to start server");

    assert!(err.is::<MidLevel>());
    let mid = err.downcast_ref::<MidLevel>().unwrap();
    assert_eq!(mid.to_string(), "failed to load config");

    assert!(err.is::<LowLevel>());
    let low = err.downcast_ref::<LowLevel>().unwrap();
    assert_eq!(low.to_string(), "no such file or directory");

    assert!(dropped.none());
    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_high() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<HighLevel>().unwrap();
    assert!(!dropped.high.get());
    assert!(dropped.low.get() && dropped.mid.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_mid() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<MidLevel>().unwrap();
    assert!(!dropped.mid.get());
    assert!(dropped.low.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_downcast_low() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<LowLevel>().unwrap();
    assert!(!dropped.low.get());
    assert!(dropped.mid.get() && dropped.high.get());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_unsuccessful_downcast() {
    let (err, dropped) = make_chain();

    let err = err.downcast::<String>().unwrap_err();
    assert!(dropped.none());

    drop(err);
    assert!(dropped.all());
}

#[test]
fn test_root_cause() {
    let (err, _) = make_chain();

    assert_eq!(err.root_cause().to_string(), "no such file or directory");
}
<|endoftext|>


<commit_before>use layout::{AnonymousBlock, BlockNode, InlineNode, LayoutBox, Rect};
use css::{ColorValue, Color};
use std::iter::range;

/// Paint a tree of LayoutBoxes to an array of pixels.
pub fn paint(layout_root: &LayoutBox, bounds: Rect) -> Canvas {
    let display_list = build_display_list(layout_root);
    let mut canvas = Canvas::new(bounds.width as uint, bounds.height as uint);
    for item in display_list.iter() {
        canvas.paint_item(item);
    }
    return canvas;
}

#[deriving(Show)]
enum DisplayItem {
    SolidColor(Color, Rect),
}

type DisplayList = Vec<DisplayItem>;

pub fn build_display_list(layout_root: &LayoutBox) -> DisplayList {
    let mut list = Vec::new();
    render_layout_box(&mut list, layout_root);
    return list;
}

fn render_layout_box(list: &mut DisplayList, layout_box: &LayoutBox) {
    render_background(list, layout_box);
    render_borders(list, layout_box);
    for child in layout_box.children.iter() {
        render_layout_box(list, child);
    }
}

fn render_background(list: &mut DisplayList, layout_box: &LayoutBox) {
    get_color(layout_box, "background").map(|color|
        list.push(SolidColor(color, layout_box.dimensions.padding_box())));
}

fn render_borders(list: &mut DisplayList, layout_box: &LayoutBox) {
    let color = match get_color(layout_box, "border-color") {
        Some(color) => color,
        _ => return
    };

    let d = &layout_box.dimensions;
    let border_box = d.border_box();

    // Left border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y,
        width: d.border.left,
        height: border_box.height,
    }));

    // Right border
    list.push(SolidColor(color, Rect {
        x: border_box.x + border_box.width - d.border.right,
        y: border_box.y,
        width: d.border.right,
        height: border_box.height,
    }));

    // Top border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y,
        width: border_box.width,
        height: d.border.top,
    }));

    // Bottom border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y + border_box.height - d.border.bottom,
        width: border_box.width,
        height: d.border.bottom,
    }));
}

fn get_color(layout_box: &LayoutBox, name: &str) -> Option<Color> {
    match layout_box.box_type {
        BlockNode(style) | InlineNode(style) => match style.value(name) {
            Some(ColorValue(color)) => Some(color),
            _ => None
        },
        AnonymousBlock => None
    }
}

pub struct Canvas {
    pub pixels: Vec<Color>,
    pub width: uint,
    pub height: uint,
}

impl Canvas {
    fn new(width: uint, height: uint) -> Canvas {
        let white = Color { r: 255, g: 255, b: 255, a: 255 };
        return Canvas {
            pixels: Vec::from_elem(width * height, white),
            width: width,
            height: height,
        }
    }

    fn paint_item(&mut self, item: &DisplayItem) {
        match item {
            &SolidColor(color, rect) => {
                // Clip the rectangle to the canvas boundaries.
                let x0 = rect.x.max(0.0) as uint;
                let y0 = rect.y.max(0.0) as uint;
                let x1 = (rect.x + rect.width).min(self.width as f32) as uint;
                let y1 = (rect.y + rect.height).min(self.height as f32) as uint;

                for x in range(x0, x1) {
                    for y in range(y0, y1) {
                        // TODO: alpha compositing with existing pixel
                        self.pixels[x + y * self.width] = color;
                    }
                }
            }
        }
    }
}
<commit_msg>Really fix clipping<commit_after>use layout::{AnonymousBlock, BlockNode, InlineNode, LayoutBox, Rect};
use css::{ColorValue, Color};
use std::iter::range;

/// Paint a tree of LayoutBoxes to an array of pixels.
pub fn paint(layout_root: &LayoutBox, bounds: Rect) -> Canvas {
    let display_list = build_display_list(layout_root);
    let mut canvas = Canvas::new(bounds.width as uint, bounds.height as uint);
    for item in display_list.iter() {
        canvas.paint_item(item);
    }
    return canvas;
}

#[deriving(Show)]
enum DisplayItem {
    SolidColor(Color, Rect),
}

type DisplayList = Vec<DisplayItem>;

pub fn build_display_list(layout_root: &LayoutBox) -> DisplayList {
    let mut list = Vec::new();
    render_layout_box(&mut list, layout_root);
    return list;
}

fn render_layout_box(list: &mut DisplayList, layout_box: &LayoutBox) {
    render_background(list, layout_box);
    render_borders(list, layout_box);
    for child in layout_box.children.iter() {
        render_layout_box(list, child);
    }
}

fn render_background(list: &mut DisplayList, layout_box: &LayoutBox) {
    get_color(layout_box, "background").map(|color|
        list.push(SolidColor(color, layout_box.dimensions.padding_box())));
}

fn render_borders(list: &mut DisplayList, layout_box: &LayoutBox) {
    let color = match get_color(layout_box, "border-color") {
        Some(color) => color,
        _ => return
    };

    let d = &layout_box.dimensions;
    let border_box = d.border_box();

    // Left border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y,
        width: d.border.left,
        height: border_box.height,
    }));

    // Right border
    list.push(SolidColor(color, Rect {
        x: border_box.x + border_box.width - d.border.right,
        y: border_box.y,
        width: d.border.right,
        height: border_box.height,
    }));

    // Top border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y,
        width: border_box.width,
        height: d.border.top,
    }));

    // Bottom border
    list.push(SolidColor(color, Rect {
        x: border_box.x,
        y: border_box.y + border_box.height - d.border.bottom,
        width: border_box.width,
        height: d.border.bottom,
    }));
}

fn get_color(layout_box: &LayoutBox, name: &str) -> Option<Color> {
    match layout_box.box_type {
        BlockNode(style) | InlineNode(style) => match style.value(name) {
            Some(ColorValue(color)) => Some(color),
            _ => None
        },
        AnonymousBlock => None
    }
}

pub struct Canvas {
    pub pixels: Vec<Color>,
    pub width: uint,
    pub height: uint,
}

impl Canvas {
    fn new(width: uint, height: uint) -> Canvas {
        let white = Color { r: 255, g: 255, b: 255, a: 255 };
        return Canvas {
            pixels: Vec::from_elem(width * height, white),
            width: width,
            height: height,
        }
    }

    fn paint_item(&mut self, item: &DisplayItem) {
        match item {
            &SolidColor(color, rect) => {
                // Clip the rectangle to the canvas boundaries.
                let x0 = rect.x.clamp(0.0, self.width as f32) as uint;
                let y0 = rect.y.clamp(0.0, self.height as f32) as uint;
                let x1 = (rect.x + rect.width).clamp(0.0, self.width as f32) as uint;
                let y1 = (rect.y + rect.height).clamp(0.0, self.height as f32) as uint;

                for x in range(x0, x1) {
                    for y in range(y0, y1) {
                        // TODO: alpha compositing with existing pixel
                        self.pixels[x + y * self.width] = color;
                    }
                }
            }
        }
    }
}

trait FloatClamp : FloatMath {
    fn clamp(self, lower: Self, upper: Self) -> Self {
        self.max(lower).min(upper)
    }
}
impl<T: FloatMath> FloatClamp for T {}
<|endoftext|>


<commit_before>extern crate redis;

use flowgger::config::Config;
use flowgger::decoder::Decoder;
use flowgger::encoder::Encoder;
use self::redis::{Commands, RedisResult};
use std::io::{stderr, Write};
use std::sync::mpsc::SyncSender;
use super::Input;

const DEFAULT_CONNECT: &'static str = "127.0.0.1";
const DEFAULT_QUEUE_KEY: &'static str = "logs";

pub struct RedisInput {
    connect: String,
    queue_key: String,
    queue_key_tmp: String
}

impl RedisInput {
    pub fn new(config: &Config) -> RedisInput {
        let connect = config.lookup("input.redis_connect").map_or(DEFAULT_CONNECT, |x|x.as_str().
            expect("input.redis_connect must be an ip:port string")).to_owned();
        let queue_key = config.lookup("input.redis_queue_key").map_or(DEFAULT_QUEUE_KEY, |x|x.as_str().
            expect("input.redis_queue_key must be a string")).to_owned();
        let queue_key_tmp = queue_key.clone() + ".tmp";
        RedisInput {
            connect: connect,
            queue_key: queue_key,
            queue_key_tmp: queue_key_tmp
        }
    }
}

impl Input for RedisInput {
    fn accept(&self, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder + Send>, encoder: Box<Encoder + Send>) {
        let redis_cnx = match redis::Client::open(format!("redis://{}/", self.connect).as_ref()) {
            Err(_) => panic!("Invalid connection string for the Redis server: [{}]", self.connect),
            Ok(client) => match client.get_connection() {
                Err(_) => panic!("Unable to connect to the Redis server: [{}]", self.connect),
                Ok(redis_cnx) => redis_cnx
            }
        };
        println!("Connected to Redis [{}], pulling messages from key [{}]", self.connect, self.queue_key);
        while {
            let dummy: RedisResult<()> = redis_cnx.rpoplpush(self.queue_key_tmp.clone(), self.queue_key.clone());
            dummy.is_ok()
        } { };
        let (decoder, encoder): (Box<Decoder>, Box<Encoder>) = (decoder, encoder);
        loop {
            let line: String = match redis_cnx.brpoplpush(self.queue_key.clone(), self.queue_key_tmp.clone(), 0) {
                Err(_) => panic!("Redis protocol error in BRPOPLPUSH"),
                Ok(line) => line
            };
            if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
            }
            match redis_cnx.lrem(self.queue_key.clone(), 1, line) {
                Err(_) => panic!("Redis protocol error in LREM"),
                Ok(()) => ()
            };
        }
    }
}

fn handle_line(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &Box<Decoder>, encoder: &Box<Encoder>) -> Result<(), &'static str> {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<commit_msg>Redis: avoid copies for queue names<commit_after>extern crate redis;

use flowgger::config::Config;
use flowgger::decoder::Decoder;
use flowgger::encoder::Encoder;
use self::redis::{Commands, RedisResult};
use std::io::{stderr, Write};
use std::sync::mpsc::SyncSender;
use super::Input;

const DEFAULT_CONNECT: &'static str = "127.0.0.1";
const DEFAULT_QUEUE_KEY: &'static str = "logs";

pub struct RedisInput {
    connect: String,
    queue_key: String,
    queue_key_tmp: String
}

impl RedisInput {
    pub fn new(config: &Config) -> RedisInput {
        let connect = config.lookup("input.redis_connect").map_or(DEFAULT_CONNECT, |x|x.as_str().
            expect("input.redis_connect must be an ip:port string")).to_owned();
        let queue_key = config.lookup("input.redis_queue_key").map_or(DEFAULT_QUEUE_KEY, |x|x.as_str().
            expect("input.redis_queue_key must be a string")).to_owned();
        let queue_key_tmp = queue_key.clone() + ".tmp";
        RedisInput {
            connect: connect,
            queue_key: queue_key,
            queue_key_tmp: queue_key_tmp
        }
    }
}

impl Input for RedisInput {
    fn accept(&self, tx: SyncSender<Vec<u8>>, decoder: Box<Decoder + Send>, encoder: Box<Encoder + Send>) {
        let redis_cnx = match redis::Client::open(format!("redis://{}/", self.connect).as_ref()) {
            Err(_) => panic!("Invalid connection string for the Redis server: [{}]", self.connect),
            Ok(client) => match client.get_connection() {
                Err(_) => panic!("Unable to connect to the Redis server: [{}]", self.connect),
                Ok(redis_cnx) => redis_cnx
            }
        };
        println!("Connected to Redis [{}], pulling messages from key [{}]", self.connect, self.queue_key);
        let (queue_key, queue_key_tmp): (&str, &str) = (&self.queue_key, &self.queue_key_tmp);
        while {
            let dummy: RedisResult<()> = redis_cnx.rpoplpush(queue_key_tmp, queue_key);
            dummy.is_ok()
        } { };
        let (decoder, encoder): (Box<Decoder>, Box<Encoder>) = (decoder, encoder);
        loop {
            let line: String = match redis_cnx.brpoplpush(queue_key, queue_key_tmp, 0) {
                Err(_) => panic!("Redis protocol error in BRPOPLPUSH"),
                Ok(line) => line
            };
            if let Err(e) = handle_line(&line, &tx, &decoder, &encoder) {
                let _ = writeln!(stderr(), "{}: [{}]", e, line.trim());
            }
            match redis_cnx.lrem(self.queue_key.clone(), 1, line) {
                Err(_) => panic!("Redis protocol error in LREM"),
                Ok(()) => ()
            };
        }
    }
}

fn handle_line(line: &String, tx: &SyncSender<Vec<u8>>, decoder: &Box<Decoder>, encoder: &Box<Encoder>) -> Result<(), &'static str> {
    let decoded = try!(decoder.decode(&line));
    let reencoded = try!(encoder.encode(decoded));
    tx.send(reencoded).unwrap();
    Ok(())
}
<|endoftext|>


<commit_before>use std::f64::consts::PI;

use geo::prelude::*;
use mint::{ColumnMatrix3, Vector3};

#[derive(Clone, Debug)]
struct PlanetCam {
    latitude: f64,
    longitude: f64,
    bearing: f64,
    pitch: f64,
    height: f64,
}

impl PlanetCam {
    fn move_forward(&mut self, meters: f64) {
        if meters == 0.0 {
            return;
        }

        let start = geo::Point::new(self.longitude, self.latitude);
        let end = start.haversine_destination(self.bearing, meters);
        let new_bearing =
            if meters > 0.0 { end.bearing(start) + 180.0 } else { end.bearing(start) };

        assert_eq!(start.lat(), self.latitude);
        assert_eq!(start.lng(), self.longitude);

        self.latitude = end.lat();
        self.longitude = end.lng();
        self.bearing = new_bearing;
    }
    fn move_right(&mut self, meters: f64) {
        if meters == 0.0 {
            return;
        }

        let start = geo::Point::new(self.longitude, self.latitude);
        let end = start.haversine_destination(self.bearing + 90.0, meters);
        let new_bearing =
            if meters > 0.0 { end.bearing(start) + 90.0 } else { end.bearing(start) - 90.0 };

        self.latitude = end.lat().min(89.999).max(-89.999);
        self.longitude = end.lng();
        self.bearing = new_bearing;
    }
    fn move_up(&mut self, meters: f64) {
        self.height = (self.height + meters).max(0.001);
    }

    fn increase_bearing(&mut self, degrees: f64) {
        self.bearing += degrees;
        if self.bearing >= 360.0 {
            self.bearing -= 360.0;
        }
        if self.bearing < 0.0 {
            self.bearing += 360.0;
        }
    }
    fn increase_pitch(&mut self, degrees: f64) {
        self.pitch += degrees;
        self.pitch = self.pitch.min(89.0).max(-89.0);
    }

    /// Returns the ECEF position and the view matrix associated with this camera.
    fn position_view(&self, terrain_elevation: f64) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        let r = 6371000.0 + self.height + terrain_elevation;
        let lat = self.latitude.to_radians();
        let long = self.longitude.to_radians();

        let up = cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());
        let position = up * r;

        let adjusted_pitch = (self.pitch.to_radians() - f64::acos(6371000.0 / r)).clamp(-0.499 * PI, 0.499 * PI);

        let start = geo::Point::new(self.longitude, self.latitude);
        let center = start.haversine_destination(self.bearing, 1.0);
        let latc = center.lat().to_radians();
        let longc = center.lng().to_radians();
        let forward = (1.0 + adjusted_pitch.tan() / 6371000.0)
            * cgmath::Vector3::new(latc.cos() * longc.cos(), latc.cos() * longc.sin(), latc.sin())
            - up;

        let matrix = cgmath::Matrix3::look_to_rh(forward, up);
        (position.into(), matrix.cast().unwrap().into())
    }
}

pub struct DualPlanetCam {
    anchored: Option<PlanetCam>,
    free: PlanetCam,
}
impl DualPlanetCam {
    pub fn new(latitude: f64, longitude: f64, bearing: f64, pitch: f64, height: f64) -> Self {
        Self { anchored: None, free: PlanetCam { latitude, longitude, bearing, pitch, height } }
    }

    pub fn detach(&mut self) {
        self.anchored = Some(self.free.clone());
    }
    pub fn attach(&mut self) {
        self.anchored = None;
    }
    pub fn is_detached(&self) -> bool {
        self.anchored.is_some()
    }

    pub fn move_forward(&mut self, meters: f64) {
        self.free.move_forward(meters);
    }
    pub fn move_right(&mut self, meters: f64) {
        self.free.move_right(meters);
    }
    pub fn move_up(&mut self, meters: f64) {
        self.free.move_up(meters);
    }

    pub fn increase_bearing(&mut self, degrees: f64) {
        self.free.increase_bearing(degrees);
    }
    pub fn increase_pitch(&mut self, degrees: f64) {
        self.free.increase_pitch(degrees);
    }

    pub fn latitude_longitude(&self) -> (f64, f64) {
        (self.free.latitude, self.free.longitude)
    }
    pub fn height(&self) -> f64 {
        self.free.height
    }

    pub fn anchored_latitude_longitude(&self) -> (f64, f64) {
        let c = self.anchored.as_ref().unwrap_or(&self.free);
        (c.latitude, c.longitude)
    }

    pub fn anchored_position_view(
        &self,
        terrain_elevation: f64,
    ) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        match &self.anchored {
            Some(a) => a.position_view(terrain_elevation),
            None => self.free.position_view(terrain_elevation),
        }
    }
    pub fn free_position_view(&self, terrain_elevation: f64) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        self.free.position_view(terrain_elevation)
    }
}

#[cfg(test)]
mod tests {
    use cgmath::{assert_abs_diff_eq, assert_relative_eq, MetricSpace};
    use geo::prelude::HaversineDestination;

    use crate::PlanetCam;

    #[test]
    fn it_works() {
        let camera =
            PlanetCam { latitude: 23.0, longitude: 45.0, height: 100.0, bearing: 67.0, pitch: 0.0 };
        let mut camera2 = camera.clone();
        for x in 1..100 {
            let mut full = camera.clone();
            full.move_forward(10000.0 * x as f64);

            camera2.move_forward(10000.0);

            assert_abs_diff_eq!(full.latitude, camera2.latitude, epsilon = 0.0001);
            assert_abs_diff_eq!(full.longitude, camera2.longitude, epsilon = 0.0001);
        }
    }

    #[test]
    fn move_distance() {
        let camera =
            PlanetCam { latitude: 23.0, longitude: 45.0, height: 100.0, bearing: 67.0, pitch: 0.0 };
        let mut camera2 = camera.clone();
        camera2.move_forward(100.0);

        const MEAN_EARTH_RADIUS: f64 = 6371008.8;
        const MEAN_EARTH_CIRCUMFERENCE: f64 = MEAN_EARTH_RADIUS * std::f64::consts::PI;

        let (lat, long) = (camera.latitude.to_radians(), camera.longitude.to_radians());
        let position = MEAN_EARTH_RADIUS
            * cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());

        let (lat, long) = (camera2.latitude.to_radians(), camera2.longitude.to_radians());
        let position2 = MEAN_EARTH_RADIUS
            * cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());

        let distance = position.distance(position2);
        assert_abs_diff_eq!(distance, 100.0, epsilon = 0.1);

        let start = geo::Point::new(camera.longitude, 0.0);
        let end = start.haversine_destination(0.0, 1000.0);
        assert_abs_diff_eq!(
            end.lat() - start.lat(),
            1000.0 * 180.0 / MEAN_EARTH_CIRCUMFERENCE,
            epsilon = 0.0000001
        );

        let end = start.haversine_destination(90.0, 1000.0);
        assert_abs_diff_eq!(
            end.lng() - start.lng(),
            1000.0 * 180.0 / MEAN_EARTH_CIRCUMFERENCE,
            epsilon = 0.0000001
        );
    }
}
<commit_msg>Fix warnings<commit_after>use std::f64::consts::PI;

use geo::prelude::*;
use mint::{ColumnMatrix3, Vector3};

#[derive(Clone, Debug)]
struct PlanetCam {
    latitude: f64,
    longitude: f64,
    bearing: f64,
    pitch: f64,
    height: f64,
}

impl PlanetCam {
    fn move_forward(&mut self, meters: f64) {
        if meters == 0.0 {
            return;
        }

        let start = geo::Point::new(self.longitude, self.latitude);
        let end = start.haversine_destination(self.bearing, meters);
        let new_bearing =
            if meters > 0.0 { end.bearing(start) + 180.0 } else { end.bearing(start) };

        assert_eq!(start.y(), self.latitude);
        assert_eq!(start.x(), self.longitude);

        self.latitude = end.y();
        self.longitude = end.x();
        self.bearing = new_bearing;
    }
    fn move_right(&mut self, meters: f64) {
        if meters == 0.0 {
            return;
        }

        let start = geo::Point::new(self.longitude, self.latitude);
        let end = start.haversine_destination(self.bearing + 90.0, meters);
        let new_bearing =
            if meters > 0.0 { end.bearing(start) + 90.0 } else { end.bearing(start) - 90.0 };

        self.latitude = end.y().min(89.999).max(-89.999);
        self.longitude = end.x();
        self.bearing = new_bearing;
    }
    fn move_up(&mut self, meters: f64) {
        self.height = (self.height + meters).max(0.001);
    }

    fn increase_bearing(&mut self, degrees: f64) {
        self.bearing += degrees;
        if self.bearing >= 360.0 {
            self.bearing -= 360.0;
        }
        if self.bearing < 0.0 {
            self.bearing += 360.0;
        }
    }
    fn increase_pitch(&mut self, degrees: f64) {
        self.pitch += degrees;
        self.pitch = self.pitch.min(89.0).max(-89.0);
    }

    /// Returns the ECEF position and the view matrix associated with this camera.
    fn position_view(&self, terrain_elevation: f64) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        let r = 6371000.0 + self.height + terrain_elevation;
        let lat = self.latitude.to_radians();
        let long = self.longitude.to_radians();

        let up = cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());
        let position = up * r;

        let adjusted_pitch = (self.pitch.to_radians() - f64::acos(6371000.0 / r)).clamp(-0.499 * PI, 0.499 * PI);

        let start = geo::Point::new(self.longitude, self.latitude);
        let center = start.haversine_destination(self.bearing, 1.0);
        let latc = center.y().to_radians();
        let longc = center.x().to_radians();
        let forward = (1.0 + adjusted_pitch.tan() / 6371000.0)
            * cgmath::Vector3::new(latc.cos() * longc.cos(), latc.cos() * longc.sin(), latc.sin())
            - up;

        let matrix = cgmath::Matrix3::look_to_rh(forward, up);
        (position.into(), matrix.cast().unwrap().into())
    }
}

pub struct DualPlanetCam {
    anchored: Option<PlanetCam>,
    free: PlanetCam,
}
impl DualPlanetCam {
    pub fn new(latitude: f64, longitude: f64, bearing: f64, pitch: f64, height: f64) -> Self {
        Self { anchored: None, free: PlanetCam { latitude, longitude, bearing, pitch, height } }
    }

    pub fn detach(&mut self) {
        self.anchored = Some(self.free.clone());
    }
    pub fn attach(&mut self) {
        self.anchored = None;
    }
    pub fn is_detached(&self) -> bool {
        self.anchored.is_some()
    }

    pub fn move_forward(&mut self, meters: f64) {
        self.free.move_forward(meters);
    }
    pub fn move_right(&mut self, meters: f64) {
        self.free.move_right(meters);
    }
    pub fn move_up(&mut self, meters: f64) {
        self.free.move_up(meters);
    }

    pub fn increase_bearing(&mut self, degrees: f64) {
        self.free.increase_bearing(degrees);
    }
    pub fn increase_pitch(&mut self, degrees: f64) {
        self.free.increase_pitch(degrees);
    }

    pub fn latitude_longitude(&self) -> (f64, f64) {
        (self.free.latitude, self.free.longitude)
    }
    pub fn height(&self) -> f64 {
        self.free.height
    }

    pub fn anchored_latitude_longitude(&self) -> (f64, f64) {
        let c = self.anchored.as_ref().unwrap_or(&self.free);
        (c.latitude, c.longitude)
    }

    pub fn anchored_position_view(
        &self,
        terrain_elevation: f64,
    ) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        match &self.anchored {
            Some(a) => a.position_view(terrain_elevation),
            None => self.free.position_view(terrain_elevation),
        }
    }
    pub fn free_position_view(&self, terrain_elevation: f64) -> (Vector3<f64>, ColumnMatrix3<f32>) {
        self.free.position_view(terrain_elevation)
    }
}

#[cfg(test)]
mod tests {
    use cgmath::{assert_abs_diff_eq, assert_relative_eq, MetricSpace};
    use geo::prelude::HaversineDestination;

    use crate::PlanetCam;

    #[test]
    fn it_works() {
        let camera =
            PlanetCam { latitude: 23.0, longitude: 45.0, height: 100.0, bearing: 67.0, pitch: 0.0 };
        let mut camera2 = camera.clone();
        for x in 1..100 {
            let mut full = camera.clone();
            full.move_forward(10000.0 * x as f64);

            camera2.move_forward(10000.0);

            assert_abs_diff_eq!(full.latitude, camera2.latitude, epsilon = 0.0001);
            assert_abs_diff_eq!(full.longitude, camera2.longitude, epsilon = 0.0001);
        }
    }

    #[test]
    fn move_distance() {
        let camera =
            PlanetCam { latitude: 23.0, longitude: 45.0, height: 100.0, bearing: 67.0, pitch: 0.0 };
        let mut camera2 = camera.clone();
        camera2.move_forward(100.0);

        const MEAN_EARTH_RADIUS: f64 = 6371008.8;
        const MEAN_EARTH_CIRCUMFERENCE: f64 = MEAN_EARTH_RADIUS * std::f64::consts::PI;

        let (lat, long) = (camera.latitude.to_radians(), camera.longitude.to_radians());
        let position = MEAN_EARTH_RADIUS
            * cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());

        let (lat, long) = (camera2.latitude.to_radians(), camera2.longitude.to_radians());
        let position2 = MEAN_EARTH_RADIUS
            * cgmath::Vector3::new(lat.cos() * long.cos(), lat.cos() * long.sin(), lat.sin());

        let distance = position.distance(position2);
        assert_abs_diff_eq!(distance, 100.0, epsilon = 0.1);

        let start = geo::Point::new(camera.longitude, 0.0);
        let end = start.haversine_destination(0.0, 1000.0);
        assert_abs_diff_eq!(
            end.y() - start.y(),
            1000.0 * 180.0 / MEAN_EARTH_CIRCUMFERENCE,
            epsilon = 0.0000001
        );

        let end = start.haversine_destination(90.0, 1000.0);
        assert_abs_diff_eq!(
            end.x() - start.x(),
            1000.0 * 180.0 / MEAN_EARTH_CIRCUMFERENCE,
            epsilon = 0.0000001
        );
    }
}
<|endoftext|>


<commit_before><commit_msg>Rewrite 2D sweeping along diagonal bands<commit_after><|endoftext|>


<commit_before><commit_msg>changed frustum method names<commit_after><|endoftext|>


<commit_before>pub struct PLPWriter
{
	/// If true, tabs will be used to indent. Else, spaces will be used to indent
	pub use_tabs: bool,

	/// Number of indent characters to prefix each line of code with.
	/// Adjusting this value will not affect code that has already been written
	pub indent_level: u16,

	/// PLP output of this writer
	pub code: String,

	pub annotations_enabled: bool,

	pub mapping_enabled: bool,
}

impl PLPWriter
{
	pub fn new() -> PLPWriter
	{
		PLPWriter {
			use_tabs: true,
			indent_level: 0,
			code: String::new(),
			annotations_enabled: false,
			mapping_enabled: false,
			}
	}

	pub fn copy(&self) -> PLPWriter
	{
		PLPWriter {
			use_tabs: self.use_tabs,
			indent_level: self.indent_level,
			code: String::new(),
			annotations_enabled: self.annotations_enabled,
			mapping_enabled: self.mapping_enabled,
			}
	}

	fn create_indented_string(&self) -> String
	{
		let mut string = String::new();
		let indent = match self.use_tabs {
				true  => "\t",
				false => "    ",
			};

		for _ in (0..self.indent_level)
		{
			string.push_str(indent);
		}

		string
	}

	#[allow(dead_code)]
	pub fn reset(&mut self)
	{
		self.indent_level = 0;
		self.code = String::new();
	}

	pub fn println(&mut self)
	{
		self.code.push_str("\n");
	}

	pub fn map(&mut self, comment: &str)
	{
		if self.mapping_enabled
		{
			self.comment(comment);
		}
	}

	pub fn annotate(&mut self, annotation: &str)
	{
		if self.annotations_enabled
		{
			self.comment(annotation);
		}
	}

	pub fn annotate_newline(&mut self)
	{
		if self.annotations_enabled
		{
			self.println();
		}
	}

	pub fn comment(&mut self, comment: &str)
	{
		// TODO: split by "\n" to support multi-line comments
		let mut code = self.create_indented_string();
		code.push_str("# ");
		code.push_str(comment);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn org(&mut self, address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(".org ");
		code.push_str(address);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn word(&mut self, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".word ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn equ(&mut self, symbol: &str, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".equ ");
		code.push_str(symbol);
		code.push_str(" ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn li(&mut self, register: &str, value: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("li ");
		code.push_str(register);
		code.push_str(", ");
		code.push_str(value);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mov(&mut self, register_to: &str, register_from: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("move ");
		code.push_str(register_to);
		code.push_str(", ");
		code.push_str(register_from);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn addu(&mut self, register_sum: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("addu ");
		code.push_str(register_sum);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn subu(&mut self, register_difference: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("subu ");
		code.push_str(register_difference);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mullo(&mut self, register_product: &str, register_multiplicand1: &str, register_multiplicand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("mullo ");
		code.push_str(register_product);
		code.push_str(", ");
		code.push_str(register_multiplicand1);
		code.push_str(", ");
		code.push_str(register_multiplicand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn lw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("lw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn push(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("push ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn pop(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("pop ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn call(&mut self, function_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("call ");
		code.push_str(function_label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn nop(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("nop");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn label(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(label);
		code.push_str(":");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn beq(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("beq ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn bne(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("bne ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn ret(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("return\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn j(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("j ");
		code.push_str(label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn space(&mut self, amount: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".space ");
		code.push_str(&*amount.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}
}
<commit_msg>Extend plp syntax support<commit_after>pub struct PLPWriter
{
	/// If true, tabs will be used to indent. Else, spaces will be used to indent
	pub use_tabs: bool,

	/// Number of indent characters to prefix each line of code with.
	/// Adjusting this value will not affect code that has already been written
	pub indent_level: u16,

	/// PLP output of this writer
	pub code: String,

	pub annotations_enabled: bool,

	pub mapping_enabled: bool,
}

impl PLPWriter
{
	pub fn new() -> PLPWriter
	{
		PLPWriter {
			use_tabs: true,
			indent_level: 0,
			code: String::new(),
			annotations_enabled: false,
			mapping_enabled: false,
			}
	}

	pub fn copy(&self) -> PLPWriter
	{
		PLPWriter {
			use_tabs: self.use_tabs,
			indent_level: self.indent_level,
			code: String::new(),
			annotations_enabled: self.annotations_enabled,
			mapping_enabled: self.mapping_enabled,
			}
	}

	fn create_indented_string(&self) -> String
	{
		let mut string = String::new();
		let indent = match self.use_tabs {
				true  => "\t",
				false => "    ",
			};

		for _ in (0..self.indent_level)
		{
			string.push_str(indent);
		}

		string
	}

	#[allow(dead_code)]
	pub fn reset(&mut self)
	{
		self.indent_level = 0;
		self.code = String::new();
	}

	pub fn println(&mut self)
	{
		self.code.push_str("\n");
	}

	pub fn map(&mut self, comment: &str)
	{
		if self.mapping_enabled
		{
			self.comment(comment);
		}
	}

	pub fn annotate(&mut self, annotation: &str)
	{
		if self.annotations_enabled
		{
			self.comment(annotation);
		}
	}

	pub fn annotate_newline(&mut self)
	{
		if self.annotations_enabled
		{
			self.println();
		}
	}

	pub fn comment(&mut self, comment: &str)
	{
		// TODO: split by "\n" to support multi-line comments
		let mut code = self.create_indented_string();
		code.push_str("# ");
		code.push_str(comment);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn org(&mut self, address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(".org ");
		code.push_str(address);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn word(&mut self, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".word ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn equ(&mut self, symbol: &str, initial_value: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".equ ");
		code.push_str(symbol);
		code.push_str(" ");
		code.push_str(&*initial_value.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn li(&mut self, register: &str, value: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("li ");
		code.push_str(register);
		code.push_str(", ");
		code.push_str(value);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mov(&mut self, register_to: &str, register_from: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("move ");
		code.push_str(register_to);
		code.push_str(", ");
		code.push_str(register_from);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn addu(&mut self, register_sum: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("addu ");
		code.push_str(register_sum);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn subu(&mut self, register_difference: &str, register_addend1: &str, register_addend2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("subu ");
		code.push_str(register_difference);
		code.push_str(", ");
		code.push_str(register_addend1);
		code.push_str(", ");
		code.push_str(register_addend2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn mullo(&mut self, register_product: &str, register_multiplicand1: &str, register_multiplicand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("mullo ");
		code.push_str(register_product);
		code.push_str(", ");
		code.push_str(register_multiplicand1);
		code.push_str(", ");
		code.push_str(register_multiplicand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn slt(&mut self, register_result: &str, register_operand1: &str, register_operand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("slt ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_operand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sltu(&mut self, register_result: &str, register_operand1: &str, register_operand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sltu ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_operand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sllv(&mut self, register_result: &str, register_operand1: &str, register_amount: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sllv ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_amount);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn srlv(&mut self, register_result: &str, register_operand1: &str, register_amount: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("srlv ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_amount);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn and(&mut self, register_result: &str, register_operand1: &str, register_operand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("and ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_operand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn or(&mut self, register_result: &str, register_operand1: &str, register_operand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("or ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_operand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn nor(&mut self, register_result: &str, register_operand1: &str, register_operand2: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("nor ");
		code.push_str(register_result);
		code.push_str(", ");
		code.push_str(register_operand1);
		code.push_str(", ");
		code.push_str(register_operand2);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn sw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("sw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn lw(&mut self, register_target: &str, offset: u16, register_address: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("lw ");
		code.push_str(register_target);
		code.push_str(", ");
		code.push_str(&*offset.to_string());
		code.push_str("(");
		code.push_str(register_address);
		code.push_str(")\n");

		self.code.push_str(&*code);
	}

	pub fn push(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("push ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn pop(&mut self, register_target: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("pop ");
		code.push_str(register_target);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn call(&mut self, function_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("call ");
		code.push_str(function_label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn nop(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("nop");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn label(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str(label);
		code.push_str(":");
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn beq(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("beq ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	#[allow(dead_code)]
	pub fn bne(&mut self, register_comparator1: &str, register_comparator2: &str, target_label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("bne ");
		code.push_str(register_comparator1);
		code.push_str(", ");
		code.push_str(register_comparator2);
		code.push_str(", ");
		code.push_str(target_label);
		code.push_str("\n");

		self.code.push_str(&*code);
	}

	pub fn ret(&mut self)
	{
		let mut code = self.create_indented_string();
		code.push_str("return\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn j(&mut self, label: &str)
	{
		let mut code = self.create_indented_string();
		code.push_str("j ");
		code.push_str(label);
		code.push_str("\n");

		self.code.push_str(&*code);
		self.nop();
	}

	pub fn space(&mut self, amount: u16)
	{
		let mut code = self.create_indented_string();
		code.push_str(".space ");
		code.push_str(&*amount.to_string());
		code.push_str("\n");

		self.code.push_str(&*code);
	}
}
<|endoftext|>


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

use crate::builtins::Lazy;
use crate::builtins::WasmbinCountable;
use crate::builtins::{Blob, RawBlob};
use crate::indices::{FuncId, GlobalId, LocalId, MemId, TableId, TypeId};
use crate::instructions::Expression;
use crate::io::{Decode, DecodeError, DecodeWithDiscriminant, Encode, Wasmbin};
#[cfg(feature = "bulk-memory-operations")]
use crate::types::RefType;
use crate::types::{FuncType, GlobalType, MemType, TableType, ValueType};
use crate::visit::Visit;
use crate::wasmbin_discriminants;
use arbitrary::Arbitrary;
use custom_debug::CustomDebug;
use std::convert::TryFrom;

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ModuleNameSubSection {
    pub name: String,
}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct NameAssoc<I, V> {
    pub index: I,
    pub value: V,
}

impl<I, V> WasmbinCountable for NameAssoc<I, V> {}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct NameMap<I, V> {
    pub items: Vec<NameAssoc<I, V>>,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum NameSubSection {
    Module(Blob<String>) = 0,
    Func(Blob<NameMap<FuncId, String>>) = 1,
    Local(Blob<NameMap<FuncId, NameMap<LocalId, String>>>) = 2,
}

impl Encode for [NameSubSection] {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        for sub in self {
            sub.encode(w)?;
        }
        Ok(())
    }
}

impl Decode for Vec<NameSubSection> {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut sub = Vec::new();
        while let Some(disc) = Option::decode(r)? {
            sub.push(NameSubSection::decode_with_discriminant(disc, r)?);
        }
        Ok(sub)
    }
}

#[derive(Wasmbin, CustomDebug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct RawCustomSection {
    name: String,

    #[debug(with = "custom_debug::hexbuf_str")]
    data: Vec<u8>,
}

macro_rules! define_custom_sections {
    ($($name:ident($ty:ty) = $disc:literal,)*) => {
        #[derive(Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
        pub enum CustomSection {
            $($name(Lazy<$ty>),)*
            Other(RawCustomSection),
        }

        impl Encode for CustomSection {
            fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
                match self {
                    $(CustomSection::$name(data) => {
                        $disc.encode(w)?;
                        data.encode(w)
                    })*
                    CustomSection::Other(raw) => raw.encode(w)
                }
            }
        }

        impl Decode for CustomSection {
            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                let raw = RawCustomSection::decode(r)?;
                Ok(match raw.name.as_str() {
                    $($disc => CustomSection::$name(Lazy::from_raw(raw.data)),)*
                    _ => CustomSection::Other(raw)
                })
            }
        }
    };
}

define_custom_sections! {
    Name(Vec<NameSubSection>) = "name",
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ImportDesc {
    Func(TypeId) = 0x00,
    Table(TableType) = 0x01,
    Mem(MemType) = 0x02,
    Global(GlobalType) = 0x03,
}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ImportPath {
    pub module: String,
    pub name: String,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Import {
    pub path: ImportPath,
    pub desc: ImportDesc,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Global {
    pub ty: GlobalType,
    pub init: Expression,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ExportDesc {
    Func(FuncId) = 0x00,
    Table(TableId) = 0x01,
    Mem(MemId) = 0x02,
    Global(GlobalId) = 0x03,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Export {
    pub name: String,
    pub desc: ExportDesc,
}

#[cfg(feature = "bulk-memory-operations")]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ElemKind {
    FuncRef = 0x00,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum Element {
    ActiveWithFuncs {
        offset: Expression,
        funcs: Vec<FuncId>,
    } = 0x00,
    #[cfg(feature = "bulk-memory-operations")]
    PassiveWithFuncs { kind: ElemKind, funcs: Vec<FuncId> } = 0x01,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithTableAndFuncs {
        table: TableId,
        offset: Expression,
        kind: ElemKind,
        funcs: Vec<FuncId>,
    } = 0x02,
    #[cfg(feature = "reference-types")]
    DeclarativeWithFuncs { kind: ElemKind, funcs: Vec<FuncId> } = 0x03,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithExprs {
        offset: Expression,
        exprs: Vec<Expression>,
    } = 0x04,
    #[cfg(feature = "bulk-memory-operations")]
    PassiveWithExprs { ty: RefType, exprs: Vec<Expression> } = 0x05,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithTableAndExprs {
        table: TableId,
        offset: Expression,
        ty: RefType,
        exprs: Vec<Expression>,
    } = 0x06,
    #[cfg(feature = "reference-types")]
    DeclarativeWithExprs { ty: RefType, exprs: Vec<Expression> } = 0x07,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Locals {
    pub repeat: u32,
    pub ty: ValueType,
}

#[derive(
    Wasmbin, WasmbinCountable, Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, Visit,
)]
pub struct FuncBody {
    pub locals: Vec<Locals>,
    pub expr: Expression,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum DataInit {
    Active {
        offset: Expression,
    } = 0x00,
    #[cfg(feature = "bulk-memory-operations")]
    Passive = 0x01,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithMemory {
        memory: MemId,
        offset: Expression,
    } = 0x02,
}

#[derive(Wasmbin, WasmbinCountable, CustomDebug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Data {
    pub init: DataInit,
    #[debug(with = "custom_debug::hexbuf_str")]
    pub blob: RawBlob,
}

pub trait Payload: Encode + Decode + Into<Section> {
    const KIND: Kind;

    fn try_from_ref(section: &Section) -> Option<&Blob<Self>>;
    fn try_from_mut(section: &mut Section) -> Option<&mut Blob<Self>>;
    fn try_from(section: Section) -> Result<Blob<Self>, Section>;
}

pub trait StdPayload: Payload {}

macro_rules! define_sections {
    ($($(# $attr:tt)? $name:ident($ty:ty) = $disc:literal,)*) => {
        pub mod payload {
            $($(# $attr)? pub type $name = $ty;)*
        }

        #[wasmbin_discriminants]
        #[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
        #[repr(u8)]
        pub enum Section {
            $($(# $attr)? $name(Blob<payload::$name>) = $disc,)*
        }

        #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
        #[repr(u8)]
        pub enum Kind {
            $($(# $attr)? $name = $disc,)*
        }

        impl TryFrom<u8> for Kind {
            type Error = u8;

            fn try_from(discriminant: u8) -> Result<Kind, u8> {
                Ok(match discriminant {
                    $($(# $attr)? $disc => Kind::$name,)*
                    _ => return Err(discriminant),
                })
            }
        }

        impl Ord for Kind {
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
                // Some new sections might have larger discriminants,
                // but be ordered logically between those will smaller
                // discriminants.
                //
                // To compare their Kinds in a defined order, we need an
                // intermediate enum without discriminants.
                #[derive(PartialEq, Eq, PartialOrd, Ord)]
                #[repr(u8)]
                enum OrderedRepr {
                    $($(# $attr)? $name,)*
                }

                impl From<Kind> for OrderedRepr {
                    fn from(kind: Kind) -> Self {
                        match kind {
                            $($(# $attr)? Kind::$name => Self::$name,)*
                        }
                    }
                }

                OrderedRepr::from(*self).cmp(&OrderedRepr::from(*other))
            }
        }

        impl PartialOrd for Kind {
            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
                Some(self.cmp(other))
            }
        }

        $($(# $attr)? const _: () = {
            impl From<Blob<payload::$name>> for Section {
                fn from(value: Blob<payload::$name>) -> Self {
                    Section::$name(value)
                }
            }

            impl From<payload::$name> for Section {
                fn from(value: payload::$name) -> Self {
                    Section::$name(Blob::from(value))
                }
            }

            impl Payload for payload::$name {
                const KIND: Kind = Kind::$name;

                fn try_from_ref(section: &Section) -> Option<&Blob<Self>> {
                    match section {
                        Section::$name(res) => Some(res),
                        _ => None,
                    }
                }

                fn try_from_mut(section: &mut Section) -> Option<&mut Blob<Self>> {
                    match section {
                        Section::$name(res) => Some(res),
                        _ => None,
                    }
                }

                fn try_from(section: Section) -> Result<Blob<Self>, Section> {
                    match section {
                        Section::$name(res) => Ok(res),
                        _ => Err(section),
                    }
                }
            }
        };)*

        impl Section {
            pub fn kind(&self) -> Kind {
                match self {
                    $($(# $attr)? Section::$name(_) => Kind::$name,)*
                }
            }

            pub fn try_as<T: Payload>(&self) -> Option<&Blob<T>> {
                T::try_from_ref(self)
            }

            pub fn try_as_mut<T: Payload>(&mut self) -> Option<&mut Blob<T>> {
                T::try_from_mut(self)
            }
        }

        define_sections!(@std $($(# $attr)? $name)*);
    };

    (@std $ignore_custom:ident $($(# $attr:tt)? $name:ident)*) => {
        $($(# $attr)? impl StdPayload for payload::$name {})*
    };
}

define_sections! {
    Custom(super::CustomSection) = 0,
    Type(Vec<super::FuncType>) = 1,
    Import(Vec<super::Import>) = 2,
    Function(Vec<super::TypeId>) = 3,
    Table(Vec<super::TableType>) = 4,
    Memory(Vec<super::MemType>) = 5,
    Global(Vec<super::Global>) = 6,
    Export(Vec<super::Export>) = 7,
    Start(super::FuncId) = 8,
    Element(Vec<super::Element>) = 9,
    #[cfg(feature = "bulk-memory-operations")]
    DataCount(u32) = 12,
    Code(Vec<super::Blob<super::FuncBody>>) = 10,
    Data(Vec<super::Data>) = 11,
}

impl Encode for [Section] {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        for section in self {
            section.encode(w)?;
        }
        Ok(())
    }
}

impl Decode for Vec<Section> {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut sections = Vec::new();
        let mut last_kind = Kind::Custom;
        while let Some(disc) = Option::decode(r)? {
            match Kind::try_from(disc) {
                Ok(Kind::Custom) | Err(_) => {}
                Ok(kind) => {
                    if kind <= last_kind {
                        return Err(DecodeError::SectionOutOfOrder {
                            prev: last_kind,
                            current: kind,
                        });
                    }
                    last_kind = kind;
                }
            }
            sections.push(Section::decode_with_discriminant(disc, r)?);
        }
        Ok(sections)
    }
}
<commit_msg>Add support for producers section<commit_after>// Copyright 2020 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::builtins::Lazy;
use crate::builtins::WasmbinCountable;
use crate::builtins::{Blob, RawBlob};
use crate::indices::{FuncId, GlobalId, LocalId, MemId, TableId, TypeId};
use crate::instructions::Expression;
use crate::io::{Decode, DecodeError, DecodeWithDiscriminant, Encode, Wasmbin};
#[cfg(feature = "bulk-memory-operations")]
use crate::types::RefType;
use crate::types::{FuncType, GlobalType, MemType, TableType, ValueType};
use crate::visit::Visit;
use crate::wasmbin_discriminants;
use arbitrary::Arbitrary;
use custom_debug::CustomDebug;
use std::convert::TryFrom;

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ModuleNameSubSection {
    pub name: String,
}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct NameAssoc<I, V> {
    pub index: I,
    pub value: V,
}

impl<I, V> WasmbinCountable for NameAssoc<I, V> {}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct NameMap<I, V> {
    pub items: Vec<NameAssoc<I, V>>,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum NameSubSection {
    Module(Blob<String>) = 0,
    Func(Blob<NameMap<FuncId, String>>) = 1,
    Local(Blob<NameMap<FuncId, NameMap<LocalId, String>>>) = 2,
}

impl Encode for [NameSubSection] {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        for sub in self {
            sub.encode(w)?;
        }
        Ok(())
    }
}

impl Decode for Vec<NameSubSection> {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut sub = Vec::new();
        while let Some(disc) = Option::decode(r)? {
            sub.push(NameSubSection::decode_with_discriminant(disc, r)?);
        }
        Ok(sub)
    }
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ProducerField {
    pub name: String,
    pub values: Vec<ProducerVersionedName>,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ProducerVersionedName {
    name: String,
    version: String,
}

#[derive(Wasmbin, CustomDebug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct RawCustomSection {
    name: String,

    #[debug(with = "custom_debug::hexbuf_str")]
    data: Vec<u8>,
}

macro_rules! define_custom_sections {
    ($($name:ident($ty:ty) = $disc:literal,)*) => {
        #[derive(Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
        pub enum CustomSection {
            $($name(Lazy<$ty>),)*
            Other(RawCustomSection),
        }

        impl Encode for CustomSection {
            fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
                match self {
                    $(CustomSection::$name(data) => {
                        $disc.encode(w)?;
                        data.encode(w)
                    })*
                    CustomSection::Other(raw) => raw.encode(w)
                }
            }
        }

        impl Decode for CustomSection {
            fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
                let raw = RawCustomSection::decode(r)?;
                Ok(match raw.name.as_str() {
                    $($disc => CustomSection::$name(Lazy::from_raw(raw.data)),)*
                    _ => CustomSection::Other(raw)
                })
            }
        }
    };
}

define_custom_sections! {
    Name(Vec<NameSubSection>) = "name",
    Producers(Vec<ProducerField>) = "producers",
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ImportDesc {
    Func(TypeId) = 0x00,
    Table(TableType) = 0x01,
    Mem(MemType) = 0x02,
    Global(GlobalType) = 0x03,
}

#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct ImportPath {
    pub module: String,
    pub name: String,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Import {
    pub path: ImportPath,
    pub desc: ImportDesc,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Global {
    pub ty: GlobalType,
    pub init: Expression,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ExportDesc {
    Func(FuncId) = 0x00,
    Table(TableId) = 0x01,
    Mem(MemId) = 0x02,
    Global(GlobalId) = 0x03,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Export {
    pub name: String,
    pub desc: ExportDesc,
}

#[cfg(feature = "bulk-memory-operations")]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum ElemKind {
    FuncRef = 0x00,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum Element {
    ActiveWithFuncs {
        offset: Expression,
        funcs: Vec<FuncId>,
    } = 0x00,
    #[cfg(feature = "bulk-memory-operations")]
    PassiveWithFuncs { kind: ElemKind, funcs: Vec<FuncId> } = 0x01,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithTableAndFuncs {
        table: TableId,
        offset: Expression,
        kind: ElemKind,
        funcs: Vec<FuncId>,
    } = 0x02,
    #[cfg(feature = "reference-types")]
    DeclarativeWithFuncs { kind: ElemKind, funcs: Vec<FuncId> } = 0x03,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithExprs {
        offset: Expression,
        exprs: Vec<Expression>,
    } = 0x04,
    #[cfg(feature = "bulk-memory-operations")]
    PassiveWithExprs { ty: RefType, exprs: Vec<Expression> } = 0x05,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithTableAndExprs {
        table: TableId,
        offset: Expression,
        ty: RefType,
        exprs: Vec<Expression>,
    } = 0x06,
    #[cfg(feature = "reference-types")]
    DeclarativeWithExprs { ty: RefType, exprs: Vec<Expression> } = 0x07,
}

#[derive(Wasmbin, WasmbinCountable, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Locals {
    pub repeat: u32,
    pub ty: ValueType,
}

#[derive(
    Wasmbin, WasmbinCountable, Debug, Default, Arbitrary, PartialEq, Eq, Hash, Clone, Visit,
)]
pub struct FuncBody {
    pub locals: Vec<Locals>,
    pub expr: Expression,
}

#[wasmbin_discriminants]
#[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
#[repr(u8)]
pub enum DataInit {
    Active {
        offset: Expression,
    } = 0x00,
    #[cfg(feature = "bulk-memory-operations")]
    Passive = 0x01,
    #[cfg(feature = "bulk-memory-operations")]
    ActiveWithMemory {
        memory: MemId,
        offset: Expression,
    } = 0x02,
}

#[derive(Wasmbin, WasmbinCountable, CustomDebug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
pub struct Data {
    pub init: DataInit,
    #[debug(with = "custom_debug::hexbuf_str")]
    pub blob: RawBlob,
}

pub trait Payload: Encode + Decode + Into<Section> {
    const KIND: Kind;

    fn try_from_ref(section: &Section) -> Option<&Blob<Self>>;
    fn try_from_mut(section: &mut Section) -> Option<&mut Blob<Self>>;
    fn try_from(section: Section) -> Result<Blob<Self>, Section>;
}

pub trait StdPayload: Payload {}

macro_rules! define_sections {
    ($($(# $attr:tt)? $name:ident($ty:ty) = $disc:literal,)*) => {
        pub mod payload {
            $($(# $attr)? pub type $name = $ty;)*
        }

        #[wasmbin_discriminants]
        #[derive(Wasmbin, Debug, Arbitrary, PartialEq, Eq, Hash, Clone, Visit)]
        #[repr(u8)]
        pub enum Section {
            $($(# $attr)? $name(Blob<payload::$name>) = $disc,)*
        }

        #[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
        #[repr(u8)]
        pub enum Kind {
            $($(# $attr)? $name = $disc,)*
        }

        impl TryFrom<u8> for Kind {
            type Error = u8;

            fn try_from(discriminant: u8) -> Result<Kind, u8> {
                Ok(match discriminant {
                    $($(# $attr)? $disc => Kind::$name,)*
                    _ => return Err(discriminant),
                })
            }
        }

        impl Ord for Kind {
            fn cmp(&self, other: &Self) -> std::cmp::Ordering {
                // Some new sections might have larger discriminants,
                // but be ordered logically between those will smaller
                // discriminants.
                //
                // To compare their Kinds in a defined order, we need an
                // intermediate enum without discriminants.
                #[derive(PartialEq, Eq, PartialOrd, Ord)]
                #[repr(u8)]
                enum OrderedRepr {
                    $($(# $attr)? $name,)*
                }

                impl From<Kind> for OrderedRepr {
                    fn from(kind: Kind) -> Self {
                        match kind {
                            $($(# $attr)? Kind::$name => Self::$name,)*
                        }
                    }
                }

                OrderedRepr::from(*self).cmp(&OrderedRepr::from(*other))
            }
        }

        impl PartialOrd for Kind {
            fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
                Some(self.cmp(other))
            }
        }

        $($(# $attr)? const _: () = {
            impl From<Blob<payload::$name>> for Section {
                fn from(value: Blob<payload::$name>) -> Self {
                    Section::$name(value)
                }
            }

            impl From<payload::$name> for Section {
                fn from(value: payload::$name) -> Self {
                    Section::$name(Blob::from(value))
                }
            }

            impl Payload for payload::$name {
                const KIND: Kind = Kind::$name;

                fn try_from_ref(section: &Section) -> Option<&Blob<Self>> {
                    match section {
                        Section::$name(res) => Some(res),
                        _ => None,
                    }
                }

                fn try_from_mut(section: &mut Section) -> Option<&mut Blob<Self>> {
                    match section {
                        Section::$name(res) => Some(res),
                        _ => None,
                    }
                }

                fn try_from(section: Section) -> Result<Blob<Self>, Section> {
                    match section {
                        Section::$name(res) => Ok(res),
                        _ => Err(section),
                    }
                }
            }
        };)*

        impl Section {
            pub fn kind(&self) -> Kind {
                match self {
                    $($(# $attr)? Section::$name(_) => Kind::$name,)*
                }
            }

            pub fn try_as<T: Payload>(&self) -> Option<&Blob<T>> {
                T::try_from_ref(self)
            }

            pub fn try_as_mut<T: Payload>(&mut self) -> Option<&mut Blob<T>> {
                T::try_from_mut(self)
            }
        }

        define_sections!(@std $($(# $attr)? $name)*);
    };

    (@std $ignore_custom:ident $($(# $attr:tt)? $name:ident)*) => {
        $($(# $attr)? impl StdPayload for payload::$name {})*
    };
}

define_sections! {
    Custom(super::CustomSection) = 0,
    Type(Vec<super::FuncType>) = 1,
    Import(Vec<super::Import>) = 2,
    Function(Vec<super::TypeId>) = 3,
    Table(Vec<super::TableType>) = 4,
    Memory(Vec<super::MemType>) = 5,
    Global(Vec<super::Global>) = 6,
    Export(Vec<super::Export>) = 7,
    Start(super::FuncId) = 8,
    Element(Vec<super::Element>) = 9,
    #[cfg(feature = "bulk-memory-operations")]
    DataCount(u32) = 12,
    Code(Vec<super::Blob<super::FuncBody>>) = 10,
    Data(Vec<super::Data>) = 11,
}

impl Encode for [Section] {
    fn encode(&self, w: &mut impl std::io::Write) -> std::io::Result<()> {
        for section in self {
            section.encode(w)?;
        }
        Ok(())
    }
}

impl Decode for Vec<Section> {
    fn decode(r: &mut impl std::io::Read) -> Result<Self, DecodeError> {
        let mut sections = Vec::new();
        let mut last_kind = Kind::Custom;
        while let Some(disc) = Option::decode(r)? {
            match Kind::try_from(disc) {
                Ok(Kind::Custom) | Err(_) => {}
                Ok(kind) => {
                    if kind <= last_kind {
                        return Err(DecodeError::SectionOutOfOrder {
                            prev: last_kind,
                            current: kind,
                        });
                    }
                    last_kind = kind;
                }
            }
            sections.push(Section::decode_with_discriminant(disc, r)?);
        }
        Ok(sections)
    }
}
<|endoftext|>