<commit_before>use serde_json::Value;
use std::sync::mpsc::{
    Receiver as MpscReceiver,
    Sender as MpscSender,
    TryRecvError,
};
use std::sync::{Arc, Mutex};
use std::time::{Duration as StdDuration, Instant};
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::result::WebSocketError as WsError;
use websocket::stream::WebSocketStream;
use ::constants::{self, LARGE_THRESHOLD, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    json!({
        "op": OpCode::Identify.num(),
        "d": {
            "compression": !cfg!(feature="debug"),
            "large_threshold": LARGE_THRESHOLD,
            "shard": shard_info,
            "token": token,
            "v": constants::GATEWAY_VERSION,
            "properties": {
                "$browser": "serenity",
                "$device": "serenity",
                "$os": env::consts::OS,
            },
        },
    })
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 heartbeat_sent: Arc<Mutex<Instant>>,
                 mut sender: Sender<WebSocketStream>,
                 channel: &MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;
    let mut last_successful = false;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = json!({
                "d": last_sequence,
                "op": OpCode::Heartbeat.num(),
            });

            trace!("Sending heartbeat d: {}", last_sequence);

            match sender.send_json(&map) {
                Ok(_) => {
                    let now = Instant::now();

                    *heartbeat_sent.lock().unwrap() = now;
                },
                Err(why) => {
                    match why {
                        Error::WebSocket(WsError::IoError(err)) => {
                            if err.raw_os_error() != Some(32) {
                                debug!("Err w/ keepalive: {:?}", err);
                            }
                        },
                        other => warn!("Other err w/ keepalive: {:?}", other),
                    }

                    if last_successful {
                        debug!("If next keepalive fails, closing");
                    } else {
                        break;
                    }

                    last_successful = false;
                },
            }
        }
    }

    debug!("Closing keepalive");

    match sender.shutdown_all() {
        Ok(_) => debug!("Successfully shutdown sender/receiver"),
        Err(why) => {
            // This can fail if the receiver already shutdown.
            if why.raw_os_error() != Some(107) {
                warn!("Failed to shutdown sender/receiver: {:?}", why);
            }
        },
    }
}
<commit_msg>Default to using [0, 1] shards<commit_after>use serde_json::Value;
use std::sync::mpsc::{
    Receiver as MpscReceiver,
    Sender as MpscSender,
    TryRecvError,
};
use std::sync::{Arc, Mutex};
use std::time::{Duration as StdDuration, Instant};
use std::{env, thread};
use super::super::ClientError;
use super::{GatewayError, GatewayStatus};
use time::{self, Duration};
use websocket::client::request::Url as RequestUrl;
use websocket::client::{Receiver, Sender};
use websocket::result::WebSocketError as WsError;
use websocket::stream::WebSocketStream;
use ::constants::{self, LARGE_THRESHOLD, OpCode};
use ::error::{Error, Result};
use ::internal::ws_impl::{ReceiverExt, SenderExt};
use ::model::event::{Event, GatewayEvent, ReadyEvent};

#[inline]
pub fn parse_ready(event: GatewayEvent,
                   tx: &MpscSender<GatewayStatus>,
                   receiver: &mut Receiver<WebSocketStream>,
                   identification: Value)
                   -> Result<(ReadyEvent, u64)> {
    match event {
        GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
            Ok((event, seq))
        },
        GatewayEvent::InvalidateSession => {
            debug!("Session invalidation");

            let _ = tx.send(GatewayStatus::SendMessage(identification));

            match receiver.recv_json(GatewayEvent::decode)? {
                GatewayEvent::Dispatch(seq, Event::Ready(event)) => {
                    Ok((event, seq))
                },
                other => {
                    debug!("Unexpected event: {:?}", other);

                    Err(Error::Gateway(GatewayError::InvalidHandshake))
                },
            }
        },
        other => {
            debug!("Unexpected event: {:?}", other);

            Err(Error::Gateway(GatewayError::InvalidHandshake))
        },
    }
}

pub fn identify(token: &str, shard_info: Option<[u64; 2]>) -> Value {
    json!({
        "op": OpCode::Identify.num(),
        "d": {
            "compression": !cfg!(feature="debug"),
            "large_threshold": LARGE_THRESHOLD,
            "shard": shard_info.unwrap_or([0, 1]),
            "token": token,
            "v": constants::GATEWAY_VERSION,
            "properties": {
                "$browser": "serenity",
                "$device": "serenity",
                "$os": env::consts::OS,
            },
        },
    })
}

pub fn build_gateway_url(base: &str) -> Result<RequestUrl> {
    RequestUrl::parse(&format!("{}?v={}", base, constants::GATEWAY_VERSION))
        .map_err(|_| Error::Client(ClientError::Gateway))
}

pub fn keepalive(interval: u64,
                 heartbeat_sent: Arc<Mutex<Instant>>,
                 mut sender: Sender<WebSocketStream>,
                 channel: &MpscReceiver<GatewayStatus>) {
    let mut base_interval = Duration::milliseconds(interval as i64);
    let mut next_tick = time::get_time() + base_interval;

    let mut last_sequence = 0;
    let mut last_successful = false;

    'outer: loop {
        thread::sleep(StdDuration::from_millis(100));

        loop {
            match channel.try_recv() {
                Ok(GatewayStatus::Interval(interval)) => {
                    base_interval = Duration::milliseconds(interval as i64);
                },
                Ok(GatewayStatus::Sender(new_sender)) => {
                    sender = new_sender;
                },
                Ok(GatewayStatus::SendMessage(val)) => {
                    if let Err(why) = sender.send_json(&val) {
                        warn!("Error sending message: {:?}", why);
                    }
                },
                Ok(GatewayStatus::Sequence(seq)) => {
                    last_sequence = seq;
                },
                Err(TryRecvError::Empty) => break,
                Err(TryRecvError::Disconnected) => break 'outer,
            }
        }

        if time::get_time() >= next_tick {
            next_tick = next_tick + base_interval;

            let map = json!({
                "d": last_sequence,
                "op": OpCode::Heartbeat.num(),
            });

            trace!("Sending heartbeat d: {}", last_sequence);

            match sender.send_json(&map) {
                Ok(_) => {
                    let now = Instant::now();

                    *heartbeat_sent.lock().unwrap() = now;
                },
                Err(why) => {
                    match why {
                        Error::WebSocket(WsError::IoError(err)) => {
                            if err.raw_os_error() != Some(32) {
                                debug!("Err w/ keepalive: {:?}", err);
                            }
                        },
                        other => warn!("Other err w/ keepalive: {:?}", other),
                    }

                    if last_successful {
                        debug!("If next keepalive fails, closing");
                    } else {
                        break;
                    }

                    last_successful = false;
                },
            }
        }
    }

    debug!("Closing keepalive");

    match sender.shutdown_all() {
        Ok(_) => debug!("Successfully shutdown sender/receiver"),
        Err(why) => {
            // This can fail if the receiver already shutdown.
            if why.raw_os_error() != Some(107) {
                warn!("Failed to shutdown sender/receiver: {:?}", why);
            }
        },
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::Zero,
                color_dst: BlendFactor::One,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::Zero,
                alpha_dst: BlendFactor::One,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    Collective(AttachmentBlend),
    Individual(Vec<AttachmentBlend>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<commit_msg>Add Blend::alpha_blending()<commit_after>// Copyright (c) 2016 The vulkano developers
// Licensed under the Apache License, Version 2.0
// <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT
// license <LICENSE-MIT or http://opensource.org/licenses/MIT>,
// at your option. All files in the project carrying such
// notice may not be copied, modified, or distributed except
// according to those terms.

//! Defines how the color output of the fragment shader is written to the attachment.
//!
//! There are three kinds of color attachments for the purpose of blending:
//!
//! - Attachments with a floating-point, fixed point format.
//! - Attachments with a (non-normalized) integer format.
//! - Attachments with a normalized integer format.
//!
//! For floating-point and fixed-point formats, the blending operation is applied. For integer
//! formats, the logic operation is applied. For normalized integer formats, the logic operation
//! will take precedence if it is activated, otherwise the blending operation is applied.
//!

use vk;

#[derive(Debug, Clone, PartialEq)]
pub struct Blend {
    pub logic_op: Option<LogicOp>,

    pub attachments: AttachmentsBlend,

    /// The constant color to use for the `Constant*` blending operation.
    ///
    /// If you pass `None`, then this state will be considered as dynamic and the blend constants
    /// will need to be set when you build the command buffer.
    pub blend_constants: Option<[f32; 4]>,
}

impl Blend {
    /// Returns a `Blend` object that directly writes colors and alpha on the surface.
    #[inline]
    pub fn pass_through() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::Zero,
                color_dst: BlendFactor::One,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::Zero,
                alpha_dst: BlendFactor::One,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }

    /// Returns a `Blend` object that adds transparent objects over others.
    #[inline]
    pub fn alpha_blending() -> Blend {
        Blend {
            logic_op: None,
            attachments: AttachmentsBlend::Collective(AttachmentBlend {
                enabled: false,
                color_op: BlendOp::Add,
                color_src: BlendFactor::SrcAlpha,
                color_dst: BlendFactor::OneMinusSrcAlpha,
                alpha_op: BlendOp::Add,
                alpha_src: BlendFactor::SrcAlpha,
                alpha_dst: BlendFactor::OneMinusSrcAlpha,
                mask_red: true,
                mask_green: true,
                mask_blue: true,
                mask_alpha: true,
            }),
            blend_constants: Some([0.0, 0.0, 0.0, 0.0]),
        }
    }
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub enum AttachmentsBlend {
    Collective(AttachmentBlend),
    Individual(Vec<AttachmentBlend>),
}

#[derive(Debug, Clone, PartialEq, Eq)]
pub struct AttachmentBlend {
    // TODO: could be automatically determined from the other params
    pub enabled: bool,

    pub color_op: BlendOp,
    pub color_src: BlendFactor,
    pub color_dst: BlendFactor,

    pub alpha_op: BlendOp,
    pub alpha_src: BlendFactor,
    pub alpha_dst: BlendFactor,

    pub mask_red: bool,
    pub mask_green: bool,
    pub mask_blue: bool,
    pub mask_alpha: bool,
}

#[doc(hidden)]
impl Into<vk::PipelineColorBlendAttachmentState> for AttachmentBlend {
    #[inline]
    fn into(self) -> vk::PipelineColorBlendAttachmentState {
        vk::PipelineColorBlendAttachmentState {
            blendEnable: if self.enabled { vk::TRUE } else { vk::FALSE },
            srcColorBlendFactor: self.color_src as u32,
            dstColorBlendFactor: self.color_dst as u32,
            colorBlendOp: self.color_op as u32,
            srcAlphaBlendFactor: self.alpha_src as u32,
            dstAlphaBlendFactor: self.alpha_dst as u32,
            alphaBlendOp: self.alpha_op as u32,
            colorWriteMask: {
                let mut mask = 0;
                if self.mask_red { mask |= vk::COLOR_COMPONENT_R_BIT; }
                if self.mask_green { mask |= vk::COLOR_COMPONENT_G_BIT; }
                if self.mask_blue { mask |= vk::COLOR_COMPONENT_B_BIT; }
                if self.mask_alpha { mask |= vk::COLOR_COMPONENT_A_BIT; }
                mask
            },
        }
    }
}

/// Which logical operation to apply to the output values.
///
/// The operation is applied individually for each channel (red, green, blue and alpha).
///
/// Only relevant for integer or unsigned attachments.
///
/// Also note that some implementations don't support logic operations.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum LogicOp {
    /// Returns `0`.
    Clear = vk::LOGIC_OP_CLEAR,
    /// Returns `src & dest`.
    And = vk::LOGIC_OP_AND,
    /// Returns `src & !dest`.
    AndReverse = vk::LOGIC_OP_AND_REVERSE,
    /// Returns `src`.
    Copy = vk::LOGIC_OP_COPY,
    /// Returns `!src & dest`.
    AndInverted = vk::LOGIC_OP_AND_INVERTED,
    /// Returns `dest`.
    Noop = vk::LOGIC_OP_NO_OP,
    /// Returns `src ^ dest`.
    Xor = vk::LOGIC_OP_XOR,
    /// Returns `src | dest`.
    Or = vk::LOGIC_OP_OR,
    /// Returns `!(src | dest)`.
    Nor = vk::LOGIC_OP_NOR,
    /// Returns `!(src ^ dest)`.
    Equivalent = vk::LOGIC_OP_EQUIVALENT,
    /// Returns `!dest`.
    Invert = vk::LOGIC_OP_INVERT,
    /// Returns `src | !dest.
    OrReverse = vk::LOGIC_OP_OR_REVERSE,
    /// Returns `!src`.
    CopyInverted = vk::LOGIC_OP_COPY_INVERTED,
    /// Returns `!src | dest`.
    OrInverted = vk::LOGIC_OP_OR_INVERTED,
    /// Returns `!(src & dest)`.
    Nand = vk::LOGIC_OP_NAND,
    /// Returns `!0` (all bits set to 1).
    Set = vk::LOGIC_OP_SET,
}

impl Default for LogicOp {
    #[inline]
    fn default() -> LogicOp {
        LogicOp::Noop
    }
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendOp {
    Add = vk::BLEND_OP_ADD,
    Subtract = vk::BLEND_OP_SUBTRACT,
    ReverseSubtract = vk::BLEND_OP_REVERSE_SUBTRACT,
    Min = vk::BLEND_OP_MIN,
    Max = vk::BLEND_OP_MAX,
}

#[derive(Debug, Copy, Clone, PartialEq, Eq)]
#[repr(u32)]
pub enum BlendFactor {
    Zero = vk::BLEND_FACTOR_ZERO,
    One = vk::BLEND_FACTOR_ONE,
    SrcColor = vk::BLEND_FACTOR_SRC_COLOR,
    OneMinusSrcColor = vk::BLEND_FACTOR_ONE_MINUS_SRC_COLOR,
    DstColor = vk::BLEND_FACTOR_DST_COLOR,
    OneMinusDstColor = vk::BLEND_FACTOR_ONE_MINUS_DST_COLOR,
    SrcAlpha = vk::BLEND_FACTOR_SRC_ALPHA,
    OneMinusSrcAlpha = vk::BLEND_FACTOR_ONE_MINUS_SRC_ALPHA,
    DstAlpha = vk::BLEND_FACTOR_DST_ALPHA,
    OneMinusDstAlpha = vk::BLEND_FACTOR_ONE_MINUS_DST_ALPHA,
    ConstantColor = vk::BLEND_FACTOR_CONSTANT_COLOR,
    OneMinusConstantColor = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_COLOR,
    ConstantAlpha = vk::BLEND_FACTOR_CONSTANT_ALPHA,
    OneMinusConstantAlpha = vk::BLEND_FACTOR_ONE_MINUS_CONSTANT_ALPHA,
    SrcAlphaSaturate = vk::BLEND_FACTOR_SRC_ALPHA_SATURATE,
    Src1Color = vk::BLEND_FACTOR_SRC1_COLOR,
    OneMinusSrc1Color = vk::BLEND_FACTOR_ONE_MINUS_SRC1_COLOR,
    Src1Alpha = vk::BLEND_FACTOR_SRC1_ALPHA,
    OneMinusSrc1Alpha = vk::BLEND_FACTOR_ONE_MINUS_SRC1_ALPHA,
}
<|endoftext|>


<commit_before>#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![feature(allocator_api)]
#![feature(new_uninit)]
#![recursion_limit = "256"]

extern crate alloc;

#[cfg(target_os = "windows")]
extern crate winapi;

#[macro_use]
extern crate memoffset;

mod boots;
mod bytecode;
mod cannon;
mod compiler;
mod constpool;
mod cpu;
mod disassembler;
mod driver;
mod gc;
mod handle;
mod language;
mod masm;
mod mem;
mod mode;
mod object;
mod os;
mod safepoint;
mod size;
mod stack;
mod stdlib;
mod threads;
mod timer;
mod utils;
mod vm;
mod vtable;

#[cfg(not(test))]
pub fn run() -> i32 {
    driver::start()
}
<commit_msg>remove unused feature allocator_api<commit_after>#![allow(dead_code)]
#![allow(non_camel_case_types)]
#![feature(new_uninit)]
#![recursion_limit = "256"]

extern crate alloc;

#[cfg(target_os = "windows")]
extern crate winapi;

#[macro_use]
extern crate memoffset;

mod boots;
mod bytecode;
mod cannon;
mod compiler;
mod constpool;
mod cpu;
mod disassembler;
mod driver;
mod gc;
mod handle;
mod language;
mod masm;
mod mem;
mod mode;
mod object;
mod os;
mod safepoint;
mod size;
mod stack;
mod stdlib;
mod threads;
mod timer;
mod utils;
mod vm;
mod vtable;

#[cfg(not(test))]
pub fn run() -> i32 {
    driver::start()
}
<|endoftext|>


<commit_before>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        let signed_int = optional(satisfy(|c| c == '-'))
            .and(many1::<Vec<_>, _>(digit())
                .or(satisfy(|c| c == '0')
                    .with(satisfy(|c| c == 'x' || c == 'X'))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    )
                )
            .map(|x| {
                let mut s = String::new();
                if let Some(sign) = x.0 { s.push(sign) };
                x.1.iter()
                    .fold(s, |mut s: String, i| { s.push(*i); s })
                    .parse::<isize>()
                    .unwrap()
                });

        signed_int
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::{expr, number};
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint() {
        assert_eq!(
            parser(number).parse("1234").unwrap(),
            (NumNode::IntConst(IntNode { value: 1234isize }), "")
            );
        assert_eq!(
            parser(number).parse("-1234").unwrap(),
            (NumNode::IntConst(IntNode { value: -1234isize }), "")
            );
    }

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u").unwrap(),
            (NumNode::UIntConst(UIntNode { value: 1234usize }), "")
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<commit_msg>Add tests for hex int parsing<commit_after>extern crate "parser-combinators" as parser_combinators;
use self::parser_combinators::{between, spaces, parser, many, many1, digit, optional, hex_digit, not_followed_by, satisfy, Parser, ParserExt, ParseResult};
use self::parser_combinators::primitives::{State, Stream};
use super::ast::*;
use super::ast::ExprNode::*;

pub fn number<I>(input: State<I>) -> ParseResult<NumNode, I>
    where I: Stream<Item=char> {
        let signed_int = optional(satisfy(|c| c == '-'))
            .and(many1::<Vec<_>, _>(digit())
                .or(satisfy(|c| c == '0')
                    .with(satisfy(|c| c == 'x' || c == 'X'))
                    .with(many1::<Vec<_>, _>(hex_digit()))
                    )
                )
            .map(|x| {
                let mut s = String::new();
                if let Some(sign) = x.0 { s.push(sign) };
                x.1.iter()
                    .fold(s, |mut s: String, i| { s.push(*i); s })
                    .parse::<isize>()
                    .unwrap()
                });

        signed_int
            .map(|x: isize| NumNode::IntConst(IntNode{value: x}))
            .parse_state(input)
}

pub fn name<I>(input: State<I>) -> ParseResult<NameNode, I>
    where I: Stream<Item=char> {
         let initial = satisfy(|c|
            c.is_alphabetic()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?');
        let subsequent = satisfy(|c|
            c.is_alphanumeric()
                // R6RS 'special initial' characters
                || c == '!' || c == '$' || c == '%' || c == ':' || c == '^'
                || c == '<' || c == '>' || c == '_' || c == '~' || c == '\\'
                || c == '?'
                // R6RS 'special subsequent' characters
                || c == '+' || c == '-' || c == '.' || c == '@');
        initial
            .and(many::<Vec<_>, _>(subsequent).map(|it|
                it.iter().fold(
                    String::new(),
                    |mut s: String, i| {
                        s.push(*i);
                        s
                    }
                    )
                ))
            .parse_state(input)
            .map(|x| {
                let mut s = String::new();
                s.push((x.0).0);
                s.push_str(&(x.0).1);
                (NameNode{ name: s}, x.1)
            })
}

pub fn expr<I>(input: State<I>) -> ParseResult<ExprNode, I>
    where I: Stream<Item=char> {
        let spaces = spaces();
        let sexpr = between(
            satisfy(|c| c == '('),
            satisfy(|c| c == ')'),
            parser(name)
                .and(many(parser(expr)))
                .map(|x| {
                    SExpr(SExprNode {
                        operator: x.0,
                        operands: x.1
                    })
                })
            );
        spaces.clone().with(
            sexpr
                .or(parser(name).map(Name))
            ).parse_state(input)
}

#[cfg(test)]
mod tests {
    use ::ast::*;
    use ::ast::ExprNode::*;
    use super::{expr, number};
    use super::parser_combinators::{Parser,parser};

    #[test]
    fn test_basic_ident() {
        assert_eq!(
            parser(expr).parse("ident").unwrap(),
            (Name(NameNode { name: "ident".to_string() }), "")
            );
    }

    #[test]
    fn test_basic_sexpr() {
        assert_eq!(
            parser(expr).parse("(ident arg1 arg2)").unwrap(),
            (SExpr(SExprNode {
                operator: NameNode { name: "ident".to_string() },
                operands: vec![
                    Name(NameNode { name: "arg1".to_string() }),
                    Name(NameNode { name: "arg2".to_string() })
                ]
            }), "")
            );
    }

    #[test]
    fn test_parse_sint() {
        assert_eq!(
            parser(number).parse("1234").unwrap(),
            (NumNode::IntConst(IntNode { value: 1234isize }), "")
            );
        assert_eq!(
            parser(number).parse("-1234").unwrap(),
            (NumNode::IntConst(IntNode { value: -1234isize }), "")
            );
        assert_eq!(
            parser(number).parse("0x0ff").unwrap(),
            (NumNode::IntConst(IntNode { value: 0x0ffisize }), "")
            );
        assert_eq!(
            parser(number).parse("0X0FF").unwrap(),
            (NumNode::IntConst(IntNode { value: 0x0ffisize }), "")
            );
    }

    #[test]
    fn test_parse_uint() {
        assert_eq!(
            parser(number).parse("1234u").unwrap(),
            (NumNode::UIntConst(UIntNode { value: 1234usize }), "")
            );
    }

    #[test]
    fn test_parse_float() {
        assert_eq!(
            parser(number).parse("1.0").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("1f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 1.0f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
        assert_eq!(
            parser(number).parse("22.2222f").unwrap(),
            (NumNode::FloatConst(FloatNode { value: 22.2222f64 }), "")
            );
    }

}
<|endoftext|>


<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/. */

//! Configuration options for a single run of the servo application. Created
//! from command line arguments.

use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend};
use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend};

pub struct Opts {
    urls: ~[~str],
    render_backend: BackendType,
    n_render_threads: uint,
    tile_size: uint,
    profiler_period: Option<f64>,

    /// A scale factor to apply to tiles, to allow rendering tiles at higher resolutions for
    /// testing pan and zoom code.
    zoom: uint,
}

#[allow(non_implicitly_copyable_typarams)]
pub fn from_cmdline_args(args: &[~str]) -> Opts {
    use std::getopts;

    let args = args.tail();

    let opts = ~[
        getopts::optopt(~"o"),  // output file
        getopts::optopt(~"r"),  // rendering backend
        getopts::optopt(~"s"),  // size of tiles
        getopts::optopt(~"t"),  // threads to render with
        getopts::optflagopt(~"p"),  // profiler flag and output interval
        getopts::optopt(~"z"),  // zoom level
    ];

    let opt_match = match getopts::getopts(args, opts) {
      result::Ok(m) => { copy m }
      result::Err(f) => { fail!(getopts::fail_str(copy f)) }
    };
    let urls = if opt_match.free.is_empty() {
        fail!(~"servo asks that you provide 1 or more URLs")
    } else {
        copy opt_match.free
    };

    let render_backend = match getopts::opt_maybe_str(&opt_match, ~"r") {
        Some(backend_str) => {
            if backend_str == ~"direct2d" {
                Direct2DBackend
            } else if backend_str == ~"core-graphics" {
                CoreGraphicsBackend
            } else if backend_str == ~"core-graphics-accelerated" {
                CoreGraphicsAcceleratedBackend
            } else if backend_str == ~"cairo" {
                CairoBackend
            } else if backend_str == ~"skia" {
                SkiaBackend
            } else {
                fail!(~"unknown backend type")
            }
        }
        None => SkiaBackend
    };

    let tile_size: uint = match getopts::opt_maybe_str(&opt_match, ~"s") {
        Some(tile_size_str) => uint::from_str(tile_size_str).get(),
        None => 512,
    };

    let n_render_threads: uint = match getopts::opt_maybe_str(&opt_match, ~"t") {
        Some(n_render_threads_str) => uint::from_str(n_render_threads_str).get(),
        None => 1,      // FIXME: Number of cores.
    };

    let profiler_period: Option<f64> =
        // if only flag is present, default to 5 second period
        match getopts::opt_default(&opt_match, ~"p", ~"5") {
        Some(period) => Some(f64::from_str(period).get()),
        None => None,
    };

    let zoom: uint = match getopts::opt_maybe_str(&opt_match, ~"z") {
        Some(zoom_str) => uint::from_str(zoom_str).get(),
        None => 1,
    };

    Opts {
        urls: urls,
        render_backend: render_backend,
        n_render_threads: n_render_threads,
        tile_size: tile_size,
        profiler_period: profiler_period,
        zoom: zoom,
    }
}
<commit_msg>Show the error massage if 'o' option is passed.<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/. */

//! Configuration options for a single run of the servo application. Created
//! from command line arguments.

use azure::azure_hl::{BackendType, CairoBackend, CoreGraphicsBackend};
use azure::azure_hl::{CoreGraphicsAcceleratedBackend, Direct2DBackend, SkiaBackend};

pub struct Opts {
    urls: ~[~str],
    render_backend: BackendType,
    n_render_threads: uint,
    tile_size: uint,
    profiler_period: Option<f64>,

    /// A scale factor to apply to tiles, to allow rendering tiles at higher resolutions for
    /// testing pan and zoom code.
    zoom: uint,
}

#[allow(non_implicitly_copyable_typarams)]
pub fn from_cmdline_args(args: &[~str]) -> Opts {
    use std::getopts;

    let args = args.tail();

    let opts = ~[
        getopts::optopt(~"o"),  // output file
        getopts::optopt(~"r"),  // rendering backend
        getopts::optopt(~"s"),  // size of tiles
        getopts::optopt(~"t"),  // threads to render with
        getopts::optflagopt(~"p"),  // profiler flag and output interval
        getopts::optopt(~"z"),  // zoom level
    ];

    let opt_match = match getopts::getopts(args, opts) {
      result::Ok(m) => { copy m }
      result::Err(f) => { fail!(getopts::fail_str(copy f)) }
    };
    let urls = if opt_match.free.is_empty() {
        fail!(~"servo asks that you provide 1 or more URLs")
    } else {
        copy opt_match.free
    };

    if getopts::opt_present(&opt_match, ~"o") {
        fail!(~"servo cannot treat 'o' option now.")
    }

    let render_backend = match getopts::opt_maybe_str(&opt_match, ~"r") {
        Some(backend_str) => {
            if backend_str == ~"direct2d" {
                Direct2DBackend
            } else if backend_str == ~"core-graphics" {
                CoreGraphicsBackend
            } else if backend_str == ~"core-graphics-accelerated" {
                CoreGraphicsAcceleratedBackend
            } else if backend_str == ~"cairo" {
                CairoBackend
            } else if backend_str == ~"skia" {
                SkiaBackend
            } else {
                fail!(~"unknown backend type")
            }
        }
        None => SkiaBackend
    };

    let tile_size: uint = match getopts::opt_maybe_str(&opt_match, ~"s") {
        Some(tile_size_str) => uint::from_str(tile_size_str).get(),
        None => 512,
    };

    let n_render_threads: uint = match getopts::opt_maybe_str(&opt_match, ~"t") {
        Some(n_render_threads_str) => uint::from_str(n_render_threads_str).get(),
        None => 1,      // FIXME: Number of cores.
    };

    let profiler_period: Option<f64> =
        // if only flag is present, default to 5 second period
        match getopts::opt_default(&opt_match, ~"p", ~"5") {
        Some(period) => Some(f64::from_str(period).get()),
        None => None,
    };

    let zoom: uint = match getopts::opt_maybe_str(&opt_match, ~"z") {
        Some(zoom_str) => uint::from_str(zoom_str).get(),
        None => 1,
    };

    Opts {
        urls: urls,
        render_backend: render_backend,
        n_render_threads: n_render_threads,
        tile_size: tile_size,
        profiler_period: profiler_period,
        zoom: zoom,
    }
}
<|endoftext|>


<commit_before>extern crate tempdir;

extern crate protoc;
extern crate protobuf;

use std::io;
use std::io::Read;
use std::io::Write;
use std::fs;

pub use protoc::Error;
pub use protoc::Result;

#[derive(Debug)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a[&'a str],
    /// List of .proto files to compile
    pub input: &'a[&'a str],
}

/// Like `protoc --rust_out=...` but without requiring `protoc-gen-rust` command in `$PATH`.
pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    protoc.check()?;

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet = protobuf::parse_from_bytes(&fds)
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut files_to_generate = Vec::new();
    'outer:
    for file in args.input {
        for include in args.includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(io::ErrorKind::Other,
            format!("file {:?} is not found in includes {:?}", file, args.includes)));
    }

    let gen_result = protobuf::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_path_prefix<'a>(path: &'a str, mut prefix: &str) -> Option<&'a str> {
    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[.. prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1 ..])
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("xxx/abc.proto", "xxx"));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("xxx/abc.proto", "xxx/"));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("../xxx/abc.proto", "../xxx/"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<commit_msg>Better path normalization<commit_after>extern crate tempdir;

extern crate protoc;
extern crate protobuf;

use std::io;
use std::io::Read;
use std::io::Write;
use std::fs;

pub use protoc::Error;
pub use protoc::Result;

#[derive(Debug)]
pub struct Args<'a> {
    /// --lang_out= param
    pub out_dir: &'a str,
    /// -I args
    pub includes: &'a[&'a str],
    /// List of .proto files to compile
    pub input: &'a[&'a str],
}

/// Like `protoc --rust_out=...` but without requiring `protoc-gen-rust` command in `$PATH`.
pub fn run(args: Args) -> Result<()> {
    let protoc = protoc::Protoc::from_env_path();
    protoc.check()?;

    let temp_dir = tempdir::TempDir::new("protoc-rust")?;
    let temp_file = temp_dir.path().join("descriptor.pbbin");
    let temp_file = temp_file.to_str().expect("utf-8 file name");

    protoc.write_descriptor_set(protoc::DescriptorSetOutArgs {
        out: temp_file,
        includes: args.includes,
        input: args.input,
        include_imports: true,
    })?;

    let mut fds = Vec::new();
    let mut file = fs::File::open(temp_file)?;
    file.read_to_end(&mut fds)?;

    drop(file);
    drop(temp_dir);

    let fds: protobuf::descriptor::FileDescriptorSet = protobuf::parse_from_bytes(&fds)
        .map_err(|e| io::Error::new(io::ErrorKind::Other, e))?;

    let mut files_to_generate = Vec::new();
    'outer:
    for file in args.input {
        for include in args.includes {
            if let Some(truncated) = remove_path_prefix(file, include) {
                files_to_generate.push(truncated.to_owned());
                continue 'outer;
            }
        }

        return Err(Error::new(io::ErrorKind::Other,
            format!("file {:?} is not found in includes {:?}", file, args.includes)));
    }

    let gen_result = protobuf::codegen::gen(fds.get_file(), &files_to_generate);

    for r in gen_result {
        let r: protobuf::compiler_plugin::GenResult = r;
        let file = format!("{}/{}", args.out_dir, r.name);
        let mut file = fs::File::create(&file)?;
        file.write_all(&r.content)?;
        file.flush()?;
    }

    Ok(())
}

fn remove_dot_slash(path: &str) -> &str {
    if path == "." {
        ""
    } else if path.starts_with("./") || path.starts_with(".\\") {
        &path[2..]
    } else {
        path
    }
}

fn remove_path_prefix<'a>(mut path: &'a str, mut prefix: &str) -> Option<&'a str> {
    path = remove_dot_slash(path);
    prefix = remove_dot_slash(prefix);

    if prefix == "" {
        return Some(path);
    }

    if prefix.ends_with("/") || prefix.ends_with("\\") {
        prefix = &prefix[.. prefix.len() - 1];
    }

    if !path.starts_with(prefix) {
        return None;
    }

    if path.len() <= prefix.len() {
        return None;
    }

    if path.as_bytes()[prefix.len()] == b'/' || path.as_bytes()[prefix.len()] == b'\\' {
        return Some(&path[prefix.len() + 1 ..]);
    } else {
        return None;
    }
}

#[cfg(test)]
mod test {
    #[test]
    fn remove_path_prefix() {
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("xxx/abc.proto", "xxx"));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("xxx/abc.proto", "xxx/"));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("../xxx/abc.proto", "../xxx/"));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("abc.proto", "."));
        assert_eq!(Some("abc.proto"), super::remove_path_prefix("abc.proto", "./"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy"));
        assert_eq!(None, super::remove_path_prefix("xxx/abc.proto", "yyy/"));
    }
}
<|endoftext|>


<commit_before>extern crate whatlang;

use std::io;
use whatlang::{detect_lang};

fn main() {
    let mut text = String::new();
    println!("Please enter a text: ");
    io::stdin().read_line(&mut text).expect("Failed to read line");

    if let Some(lang) = detect_lang(&text) {
        println!("Language: {}", lang);
    } else {
        println!("Cannot recognize a language :(");
    }
}

<commit_msg>Update CLI example<commit_after>extern crate whatlang;

use std::io;
use whatlang::detect;

fn main() {
    let mut text = String::new();
    println!("Please enter a text:");
    io::stdin().read_line(&mut text).expect("Failed to read line");

    if let Some(info) = detect(&text) {
        println!("Language: {}", info.lang());
        println!("Confidence: {:2.0}%", info.confidence() * 100.0);
        println!("Is reliable: {}", info.is_reliable());
    } else {
        println!("Cannot recognize a language :(");
    }
}

<|endoftext|>


<commit_before>use hdr_histogram::simple_hdr_histogram::*;

#[derive(Debug)]
#[derive(Clone)]
pub struct HistogramIterationValue {
    value_iterated_to: u64,
    value_iterated_from: u64,
    count_at_value_iterated_to: u64,
    count_added_in_this_iteration_step: u64,
    total_count_to_this_value: u64,
    total_value_to_this_value: u64,
    percentile: f64,
    percentile_level_iterated_to: f64,
    integer_to_double_value_conversion_ratio: f64,
}

impl Default for HistogramIterationValue {
    fn default() -> HistogramIterationValue {
        HistogramIterationValue {
            value_iterated_to: 0,
            value_iterated_from: 0,
            count_at_value_iterated_to: 0,
            count_added_in_this_iteration_step: 0,
            total_count_to_this_value: 0,
            total_value_to_this_value: 0,
            percentile: 0.0,
            percentile_level_iterated_to: 0.0,
            integer_to_double_value_conversion_ratio: 0.0,
        }
    }
}

impl HistogramIterationValue {
    fn reset(mut self) {
        self = HistogramIterationValue { ..Default::default() };
    }
    fn set(&self, value_iterated_to: u64,
    value_iterated_from: u64,
    count_at_value_iterated_to: u64,
    count_added_in_this_iteration_step: u64,
    total_count_to_this_value: u64,
    total_value_to_this_value: u64,
    percentile: f64,
    percentile_level_iterated_to: f64,
    integer_to_double_value_conversion_ratio: f64) {

    }
}

#[derive(Debug)]
pub struct BaseHistogramIterator<T: HistogramCount> {
    histogram: SimpleHdrHistogram<T>,
    saved_histogram_total_raw_count: u64,
    current_index: usize,
    current_value_at_index: u64,
    next_value_at_index: u64,
    prev_value_iterated_to: u64,
    total_count_to_prev_index: u64,
    total_count_to_current_index: u64,
    total_value_to_current_index: u64,
    array_total_count: u64,
    count_at_this_value: T,
    fresh_sub_bucket: bool,
    current_iteration_value: HistogramIterationValue,
    integer_to_double_value_conversion_ratio: f64,
    visited_index: i32,
}

impl<T: HistogramCount> BaseHistogramIterator<T> {
    fn reset_iterator(mut self, histogram: SimpleHdrHistogram<T>) {
        self.histogram = histogram;
        self.saved_histogram_total_raw_count = self.histogram.get_count();
        self.array_total_count = self.histogram.get_count();
        self.integer_to_double_value_conversion_ratio = 0.0; //TODO should be self.histogram.integer_to_double_value_conversion_ratio
        self.current_index = 0;
        self.current_value_at_index = 0;
        self.next_value_at_index = 1 << self.histogram.get_unit_magnitude();
        self.prev_value_iterated_to = 0;
        self.total_count_to_prev_index = 0;
        self.total_count_to_current_index = 0;
        self.total_value_to_current_index = 0;
        self.count_at_this_value = T::zero();
        self.fresh_sub_bucket = true;
        self.visited_index = -1;
        self.current_iteration_value.reset();
    }
    fn exhausted_sub_buckets(&self) -> bool {
        self.current_index >= 1000 //TODO should be self.histogram.get_counts_array_length()
    }

    pub fn reached_iter_level(&self) -> bool {
        let current_count = match self.histogram.get_count_at_index(self.current_index) {
            Err(err) => 0,
            Ok(the_count) => match the_count.to_u64() {
                None => 0,
                Some(the_val) => the_val
            }
        };
        (current_count != 0) && (self.visited_index != self.current_index as i32)
    }

    pub fn get_value_iterated_to(&self) -> u64 {
        self.histogram.highest_equivalent_value(self.current_value_at_index)
    }

    pub fn get_percentile_iterated_to(&self) -> f64 {
        (100.0 * self.total_count_to_current_index as f64) / self.array_total_count as f64
    }

    pub fn increment_iteration_level(&mut self) {
        self.visited_index = self.current_index as i32;
    }

    pub fn increment_sub_bucket(&mut self) {
        self.fresh_sub_bucket = true;
        self.current_index += 1;
        self.current_value_at_index = self.histogram.value_from_index(self.current_index);
        self.next_value_at_index = self.histogram.value_from_index(self.current_index + 1);
    }
}

impl <T: HistogramCount> Iterator for BaseHistogramIterator<T> {
    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //combine Java's hasNext() and next()
        //first check if has next
        if self.histogram.get_count() != self.saved_histogram_total_raw_count {
            //in Java, this threw a ConcurrentModificationException
            return None
        }
        if self.total_count_to_current_index >= self.array_total_count {
            //this means hasNext() returns false
            return None
        }

        while ! self.exhausted_sub_buckets() {
            self.count_at_this_value = match self.histogram.get_count_at_index(self.current_index) {
                Ok(val) => val,
                Err(err) => T::zero()
            };
            if self.fresh_sub_bucket {
                let count_u64 = match self.count_at_this_value.to_u64() {
                    None => 0,
                    Some(the_long) => the_long
                };
                self.total_count_to_current_index += count_u64;
                let highest_eq_val = self.histogram.highest_equivalent_value(self.current_value_at_index);
                self.total_value_to_current_index += count_u64 * highest_eq_val;
                self.fresh_sub_bucket = false;
                if self.reached_iter_level() {
                    let value_iterated_to = self.get_value_iterated_to();
                    self.current_iteration_value.set(
                        value_iterated_to,
                        self.prev_value_iterated_to,
                        match self.count_at_this_value.to_u64() {
                            None => 0,
                            Some(the_count) => the_count
                        },
                        (self.total_count_to_current_index - self.total_count_to_prev_index),
                        self.total_count_to_current_index,
                        self.total_value_to_current_index,
                        ((100.0 * self.total_count_to_current_index as f64) / self.array_total_count as f64),
                        self.get_percentile_iterated_to(),
                        self.integer_to_double_value_conversion_ratio);
                    self.prev_value_iterated_to = value_iterated_to;
                    self.total_count_to_prev_index = self.total_count_to_current_index;
                    self.increment_iteration_level();

                    if self.histogram.get_count() != self.saved_histogram_total_raw_count {
                        //TODO this is bad
                    }

                    return Some(self.current_iteration_value.clone())
                }
                self.increment_sub_bucket();
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct RecordedValuesIterator {
    //TODO
    visited_index: u32,
}

impl Iterator for RecordedValuesIterator {
    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //TODO
        None
    }
}<commit_msg>implement set and fix borrow<commit_after>use hdr_histogram::simple_hdr_histogram::*;

#[derive(Debug)]
#[derive(Clone)]
pub struct HistogramIterationValue {
    value_iterated_to: u64,
    value_iterated_from: u64,
    count_at_value_iterated_to: u64,
    count_added_in_this_iteration_step: u64,
    total_count_to_this_value: u64,
    total_value_to_this_value: u64,
    percentile: f64,
    percentile_level_iterated_to: f64,
    integer_to_double_value_conversion_ratio: f64,
}

impl Default for HistogramIterationValue {
    fn default() -> HistogramIterationValue {
        HistogramIterationValue {
            value_iterated_to: 0,
            value_iterated_from: 0,
            count_at_value_iterated_to: 0,
            count_added_in_this_iteration_step: 0,
            total_count_to_this_value: 0,
            total_value_to_this_value: 0,
            percentile: 0.0,
            percentile_level_iterated_to: 0.0,
            integer_to_double_value_conversion_ratio: 0.0,
        }
    }
}

impl HistogramIterationValue {
    fn reset(mut self) {
        self = HistogramIterationValue { ..Default::default() };
    }
    fn set(&mut self,
            value_iterated_to: u64,
            value_iterated_from: u64,
            count_at_value_iterated_to: u64,
            count_added_in_this_iteration_step: u64,
            total_count_to_this_value: u64,
            total_value_to_this_value: u64,
            percentile: f64,
            percentile_level_iterated_to: f64,
            integer_to_double_value_conversion_ratio: f64) {
        self.value_iterated_to = value_iterated_to;
        self.value_iterated_from = value_iterated_from;
        self.count_at_value_iterated_to = count_at_value_iterated_to;
        self.count_added_in_this_iteration_step = count_added_in_this_iteration_step;
        self.total_count_to_this_value = total_count_to_this_value;
        self.total_value_to_this_value = total_value_to_this_value;
        self.percentile = percentile;
        self.percentile_level_iterated_to = percentile_level_iterated_to;
        self.integer_to_double_value_conversion_ratio = integer_to_double_value_conversion_ratio;
    }
}

#[derive(Debug)]
pub struct BaseHistogramIterator<T: HistogramCount> {
    histogram: SimpleHdrHistogram<T>,
    saved_histogram_total_raw_count: u64,
    current_index: usize,
    current_value_at_index: u64,
    next_value_at_index: u64,
    prev_value_iterated_to: u64,
    total_count_to_prev_index: u64,
    total_count_to_current_index: u64,
    total_value_to_current_index: u64,
    array_total_count: u64,
    count_at_this_value: T,
    fresh_sub_bucket: bool,
    current_iteration_value: HistogramIterationValue,
    integer_to_double_value_conversion_ratio: f64,
    visited_index: i32,
}

impl<T: HistogramCount> BaseHistogramIterator<T> {
    fn reset_iterator(mut self, histogram: SimpleHdrHistogram<T>) {
        self.histogram = histogram;
        self.saved_histogram_total_raw_count = self.histogram.get_count();
        self.array_total_count = self.histogram.get_count();
        self.integer_to_double_value_conversion_ratio = 0.0; //TODO should be self.histogram.integer_to_double_value_conversion_ratio
        self.current_index = 0;
        self.current_value_at_index = 0;
        self.next_value_at_index = 1 << self.histogram.get_unit_magnitude();
        self.prev_value_iterated_to = 0;
        self.total_count_to_prev_index = 0;
        self.total_count_to_current_index = 0;
        self.total_value_to_current_index = 0;
        self.count_at_this_value = T::zero();
        self.fresh_sub_bucket = true;
        self.visited_index = -1;
        self.current_iteration_value.reset();
    }
    fn exhausted_sub_buckets(&self) -> bool {
        self.current_index >= 1000 //TODO should be self.histogram.get_counts_array_length()
    }

    pub fn reached_iter_level(&self) -> bool {
        let current_count = match self.histogram.get_count_at_index(self.current_index) {
            Err(err) => 0,
            Ok(the_count) => match the_count.to_u64() {
                None => 0,
                Some(the_val) => the_val
            }
        };
        (current_count != 0) && (self.visited_index != self.current_index as i32)
    }

    pub fn get_value_iterated_to(&self) -> u64 {
        self.histogram.highest_equivalent_value(self.current_value_at_index)
    }

    pub fn increment_iteration_level(&mut self) {
        self.visited_index = self.current_index as i32;
    }

    pub fn increment_sub_bucket(&mut self) {
        self.fresh_sub_bucket = true;
        self.current_index += 1;
        self.current_value_at_index = self.histogram.value_from_index(self.current_index);
        self.next_value_at_index = self.histogram.value_from_index(self.current_index + 1);
    }

    pub fn get_percentile_iterated_to(total_count_to_current_index: f64, array_total_count: f64) -> f64 {
        (100.0 * total_count_to_current_index) / array_total_count
    }
}

impl <T: HistogramCount> Iterator for BaseHistogramIterator<T> {

    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //combine Java's hasNext() and next()
        //first check if has next
        if self.histogram.get_count() != self.saved_histogram_total_raw_count {
            //in Java, this threw a ConcurrentModificationException
            return None
        }
        if self.total_count_to_current_index >= self.array_total_count {
            //this means hasNext() returns false
            return None
        }

        fn get_percentile_iterated_to(total_count_to_current_index: f64, array_total_count: f64) -> f64 {
            (100.0 * total_count_to_current_index) / array_total_count
        }

        while ! self.exhausted_sub_buckets() {
            self.count_at_this_value = match self.histogram.get_count_at_index(self.current_index) {
                Ok(val) => val,
                Err(err) => T::zero()
            };
            if self.fresh_sub_bucket {
                let count_u64 = match self.count_at_this_value.to_u64() {
                    None => 0,
                    Some(the_long) => the_long
                };
                self.total_count_to_current_index += count_u64;
                let highest_eq_val = self.histogram.highest_equivalent_value(self.current_value_at_index);
                self.total_value_to_current_index += count_u64 * highest_eq_val;
                self.fresh_sub_bucket = false;
                if self.reached_iter_level() {
                    let value_iterated_to = self.get_value_iterated_to();
                    self.current_iteration_value.set(
                        value_iterated_to,
                        self.prev_value_iterated_to,
                        match self.count_at_this_value.to_u64() {
                            None => 0,
                            Some(the_count) => the_count
                        },
                        (self.total_count_to_current_index - self.total_count_to_prev_index),
                        self.total_count_to_current_index,
                        self.total_value_to_current_index,
                        ((100.0 * self.total_count_to_current_index as f64) / self.array_total_count as f64),
                        get_percentile_iterated_to(self.total_count_to_current_index as f64, self.array_total_count as f64),
                        self.integer_to_double_value_conversion_ratio);
                    self.prev_value_iterated_to = value_iterated_to;
                    self.total_count_to_prev_index = self.total_count_to_current_index;
                    self.increment_iteration_level();

                    if self.histogram.get_count() != self.saved_histogram_total_raw_count {
                        //TODO this is bad
                    }

                    return Some(self.current_iteration_value.clone())
                }
                self.increment_sub_bucket();
            }
        }
        None
    }
}

#[derive(Debug)]
pub struct RecordedValuesIterator {
    //TODO
    visited_index: u32,
}

impl Iterator for RecordedValuesIterator {
    type Item = HistogramIterationValue;
    fn next(&mut self) -> Option<Self::Item> {
        //TODO
        None
    }
}<|endoftext|>


<commit_before>extern crate linked_hash_map;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate serde;

pub mod de;
pub mod descriptor;
pub mod error;
pub mod ser;
pub mod value;

pub use error::Error;
<commit_msg>[serde_protobuf] More documentation!<commit_after>//! Support for [Google protocol buffers][1] in combination with `serde`.
//!
//! The crate is split up into several logical parts.
//!
//!   * The [`descriptor`](descriptor/index.html) module provides an API for managing dynamically
//!     loaded protocol buffer schemata.
//!   * The [`value`](value/index.html) module provides structs that can hold any raw protocol
//!     buffer decoded data (but the representation is heavily coupled with a schema).
//!   * The [`de`](de/index.html) module can be used to deserialize binary encoded protocol buffer
//!     messages given some schema descriptors.
//!
//! Serialization is not yet implemented in this version.
//!
//! [1]: https://developers.google.com/protocol-buffers/
extern crate linked_hash_map;
#[macro_use]
extern crate log;
extern crate protobuf;
extern crate serde;

pub mod de;
pub mod descriptor;
pub mod error;
pub mod ser;
pub mod value;

pub use error::Error;
<|endoftext|>


<commit_before>use alloc::{string::String, vec::Vec};
use crate::io;

use super::{Deserialize, Error, Module, Serialize, VarUint32, VarUint7, Type};
use super::index_map::IndexMap;

const NAME_TYPE_MODULE: u8 = 0;
const NAME_TYPE_FUNCTION: u8 = 1;
const NAME_TYPE_LOCAL: u8 = 2;

/// Debug name information.
#[derive(Clone, Debug, PartialEq)]
pub struct NameSection {
	/// Module name subsection.
	module: Option<ModuleNameSubsection>,

	/// Function name subsection.
	functions: Option<FunctionNameSubsection>,

	/// Local name subsection.
	locals: Option<LocalNameSubsection>,
}

impl NameSection {
	/// Creates a new name section.
	pub fn new(module: Option<ModuleNameSubsection>,
                  functions: Option<FunctionNameSubsection>,
                  locals: Option<LocalNameSubsection>) -> Self {
		Self {
			module,
			functions,
			locals,
		}
	}

	/// Module name subsection of this section.
	pub fn module(&self) -> Option<&ModuleNameSubsection> {
		self.module.as_ref()
	}

	/// Module name subsection of this section (mutable).
	pub fn module_mut(&mut self) -> &mut Option<ModuleNameSubsection> {
		&mut self.module
	}

	/// Functions name subsection of this section.
	pub fn functions(&self) -> Option<&FunctionNameSubsection> {
		self.functions.as_ref()
	}

	/// Functions name subsection of this section (mutable).
	pub fn functions_mut(&mut self) -> &mut Option<FunctionNameSubsection> {
		&mut self.functions
	}

	/// Local name subsection of this section.
	pub fn locals(&self) -> Option<&LocalNameSubsection> {
		self.locals.as_ref()
	}

	/// Local name subsection of this section (mutable).
	pub fn locals_mut(&mut self) -> &mut Option<LocalNameSubsection> {
		&mut self.locals
	}
}

impl NameSection {
	/// Deserialize a name section.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<Self, Error> {
		let mut module_name: Option<ModuleNameSubsection> = None;
		let mut function_names: Option<FunctionNameSubsection> = None;
		let mut local_names: Option<LocalNameSubsection> = None;

		loop {
			let subsection_type: u8 = match VarUint7::deserialize(rdr) {
				Ok(raw_subsection_type) => raw_subsection_type.into(),
				// todo: be more selective detecting no more subsection
				Err(_) => { break; },
			};

			// deserialize the section size
			VarUint32::deserialize(rdr)?;

			match subsection_type {
				NAME_TYPE_MODULE => {
					if let Some(_) = module_name {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
					}
					module_name = Some(ModuleNameSubsection::deserialize(rdr)?);
				},

				NAME_TYPE_FUNCTION => {
					if let Some(_) = function_names {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
					}
					function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?);
				},

				NAME_TYPE_LOCAL => {
					if let Some(_) = local_names {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL));
					}
					local_names = Some(LocalNameSubsection::deserialize(module, rdr)?);
				},

				_ => return Err(Error::UnknownNameSubsectionType(subsection_type))
			};
		}

		Ok(Self {
			module: module_name,
			functions: function_names,
			locals: local_names,
		})
	}
}

impl Serialize for NameSection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		fn serialize_subsection<W: io::Write>(wtr: &mut W, name_type: u8, name_payload: &Vec<u8>) -> Result<(), Error> {
			VarUint7::from(name_type).serialize(wtr)?;
			VarUint32::from(name_payload.len()).serialize(wtr)?;
			wtr.write(name_payload).map_err(Into::into)
		}

		if let Some(module_name_subsection) = self.module {
			let mut buffer = vec![];
			module_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?;
		}

		if let Some(function_name_subsection) = self.functions {
			let mut buffer = vec![];
			function_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?;
		}

		if let Some(local_name_subsection) = self.locals {
			let mut buffer = vec![];
			local_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?;
		}

		Ok(())
	}
}

/// The name of this module.
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleNameSubsection {
	name: String,
}

impl ModuleNameSubsection {
	/// Create a new module name section with the specified name.
	pub fn new<S: Into<String>>(name: S) -> ModuleNameSubsection {
		ModuleNameSubsection { name: name.into() }
	}

	/// The name of this module.
	pub fn name(&self) -> &str {
		&self.name
	}

	/// The name of this module (mutable).
	pub fn name_mut(&mut self) -> &mut String {
		&mut self.name
	}
}

impl Serialize for ModuleNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.name.serialize(wtr)
	}
}

impl Deserialize for ModuleNameSubsection {
	type Error = Error;

	fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSubsection, Error> {
		let name = String::deserialize(rdr)?;
		Ok(ModuleNameSubsection { name })
	}
}

/// The names of the functions in this module.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FunctionNameSubsection {
	names: NameMap,
}

impl FunctionNameSubsection {
	/// A map from function indices to names.
	pub fn names(&self) -> &NameMap {
		&self.names
	}

	/// A map from function indices to names (mutable).
	pub fn names_mut(&mut self) -> &mut NameMap {
		&mut self.names
	}

	/// Deserialize names, making sure that all names correspond to functions.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<FunctionNameSubsection, Error> {
		let names = IndexMap::deserialize(module.functions_space(), rdr)?;
		Ok(FunctionNameSubsection { names })
	}
}

impl Serialize for FunctionNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.names.serialize(wtr)
	}
}

/// The names of the local variables in this module's functions.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct LocalNameSubsection {
	local_names: IndexMap<NameMap>,
}

impl LocalNameSubsection {
	/// A map from function indices to a map from variables indices to names.
	pub fn local_names(&self) -> &IndexMap<NameMap> {
		&self.local_names
	}

	/// A map from function indices to a map from variables indices to names
	/// (mutable).
	pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
		&mut self.local_names
	}

	/// Deserialize names, making sure that all names correspond to local
	/// variables.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<LocalNameSubsection, Error> {
		let max_entry_space = module.functions_space();

		let max_signature_args = module
			.type_section()
			.map(|ts|
				ts.types()
					.iter()
					.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
					.max()
					.unwrap_or(0))
			.unwrap_or(0);

		let max_locals = module
			.code_section()
			.map(|cs| cs.bodies().iter().map(|f| f.locals().len()).max().unwrap_or(0))
			.unwrap_or(0);

		let max_space = max_signature_args + max_locals;

		let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);

		let local_names = IndexMap::deserialize_with(
			max_entry_space,
			&deserialize_locals,
			rdr,
		)?;
		Ok(LocalNameSubsection { local_names })
	}}

impl Serialize for LocalNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.local_names.serialize(wtr)
	}
}

/// A map from indices to names.
pub type NameMap = IndexMap<String>;

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

	// A helper function for the tests. Serialize a section, deserialize it,
	// and make sure it matches the original.
	fn serialize_test(original: NameSection) -> Vec<u8> {
		let mut buffer = vec![];
		original
			.serialize(&mut buffer)
			.expect("serialize error");
		buffer
		// todo: add deserialization to this test
	}

	#[test]
	fn serialize_module_name() {
		let module_name_subsection = ModuleNameSubsection::new("my_mod");
		let original = NameSection::new(Some(module_name_subsection), None, None);
		serialize_test(original.clone());
	}

	#[test]
	fn serialize_function_names() {
		let mut function_name_subsection = FunctionNameSubsection::default();
		function_name_subsection.names_mut().insert(0, "hello_world".to_string());
		let name_section = NameSection::new(None, Some(function_name_subsection), None);
		serialize_test(name_section);
	}

	#[test]
	fn serialize_local_names() {
		let mut local_name_subsection = LocalNameSubsection::default();
		let mut locals = NameMap::default();
		locals.insert(0, "msg".to_string());
		local_name_subsection.local_names_mut().insert(0, locals);

		let name_section = NameSection::new(None, None, Some(local_name_subsection));
		serialize_test(name_section);
	}

	#[test]
	fn serialize_all_subsections() {
		let module_name_subsection = ModuleNameSubsection::new("ModuleNameSubsection");

		let mut function_name_subsection = FunctionNameSubsection::default();
		function_name_subsection.names_mut().insert(0, "foo".to_string());
		function_name_subsection.names_mut().insert(1, "bar".to_string());

		let mut local_name_subsection = LocalNameSubsection::default();
		let mut locals = NameMap::default();
		locals.insert(0, "msg1".to_string());
		locals.insert(1, "msg2".to_string());
		local_name_subsection.local_names_mut().insert(0, locals);

		let name_section = NameSection::new(Some(module_name_subsection), Some(function_name_subsection), Some(local_name_subsection));
		serialize_test(name_section);
	}

	#[test]
	fn deserialize_local_names() {
		let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm")
			.expect("Should be deserialized")
			.parse_names()
			.expect("Names to be parsed");

		let name_section = module.names_section().expect("name_section should be present");
		let local_names = name_section.locals().expect("local_name_section should be present");

		let locals = local_names.local_names().get(0).expect("entry #0 should be present");
		assert_eq!(
			locals.get(0).expect("entry #0 should be present"),
			"abc"
		);

		let locals = local_names.local_names().get(1).expect("entry #1 should be present");
		assert_eq!(
			locals.get(0).expect("entry #0 should be present"),
			"def"
		);
	}
}
<commit_msg>Improve parser for name section (#298)<commit_after>use alloc::{string::String, vec::Vec};
use crate::io;

use super::{Deserialize, Error, Module, Serialize, VarUint32, VarUint7, Type};
use super::index_map::IndexMap;

const NAME_TYPE_MODULE: u8 = 0;
const NAME_TYPE_FUNCTION: u8 = 1;
const NAME_TYPE_LOCAL: u8 = 2;

/// Debug name information.
#[derive(Clone, Debug, PartialEq)]
pub struct NameSection {
	/// Module name subsection.
	module: Option<ModuleNameSubsection>,

	/// Function name subsection.
	functions: Option<FunctionNameSubsection>,

	/// Local name subsection.
	locals: Option<LocalNameSubsection>,
}

impl NameSection {
	/// Creates a new name section.
	pub fn new(module: Option<ModuleNameSubsection>,
                  functions: Option<FunctionNameSubsection>,
                  locals: Option<LocalNameSubsection>) -> Self {
		Self {
			module,
			functions,
			locals,
		}
	}

	/// Module name subsection of this section.
	pub fn module(&self) -> Option<&ModuleNameSubsection> {
		self.module.as_ref()
	}

	/// Module name subsection of this section (mutable).
	pub fn module_mut(&mut self) -> &mut Option<ModuleNameSubsection> {
		&mut self.module
	}

	/// Functions name subsection of this section.
	pub fn functions(&self) -> Option<&FunctionNameSubsection> {
		self.functions.as_ref()
	}

	/// Functions name subsection of this section (mutable).
	pub fn functions_mut(&mut self) -> &mut Option<FunctionNameSubsection> {
		&mut self.functions
	}

	/// Local name subsection of this section.
	pub fn locals(&self) -> Option<&LocalNameSubsection> {
		self.locals.as_ref()
	}

	/// Local name subsection of this section (mutable).
	pub fn locals_mut(&mut self) -> &mut Option<LocalNameSubsection> {
		&mut self.locals
	}
}

impl NameSection {
	/// Deserialize a name section.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<Self, Error> {
		let mut module_name: Option<ModuleNameSubsection> = None;
		let mut function_names: Option<FunctionNameSubsection> = None;
		let mut local_names: Option<LocalNameSubsection> = None;

		loop {
			let subsection_type: u8 = match VarUint7::deserialize(rdr) {
				Ok(raw_subsection_type) => raw_subsection_type.into(),
				// todo: be more selective detecting no more subsection
				Err(_) => { break; },
			};

			// deserialize the section size
			VarUint32::deserialize(rdr)?;

			match subsection_type {
				NAME_TYPE_MODULE => {
					if let Some(_) = module_name {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
					}
					module_name = Some(ModuleNameSubsection::deserialize(rdr)?);
				},

				NAME_TYPE_FUNCTION => {
					if let Some(_) = function_names {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_FUNCTION));
					}
					function_names = Some(FunctionNameSubsection::deserialize(module, rdr)?);
				},

				NAME_TYPE_LOCAL => {
					if let Some(_) = local_names {
						return Err(Error::DuplicatedNameSubsections(NAME_TYPE_LOCAL));
					}
					local_names = Some(LocalNameSubsection::deserialize(module, rdr)?);
				},

				_ => return Err(Error::UnknownNameSubsectionType(subsection_type))
			};
		}

		Ok(Self {
			module: module_name,
			functions: function_names,
			locals: local_names,
		})
	}
}

impl Serialize for NameSection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		fn serialize_subsection<W: io::Write>(wtr: &mut W, name_type: u8, name_payload: &Vec<u8>) -> Result<(), Error> {
			VarUint7::from(name_type).serialize(wtr)?;
			VarUint32::from(name_payload.len()).serialize(wtr)?;
			wtr.write(name_payload).map_err(Into::into)
		}

		if let Some(module_name_subsection) = self.module {
			let mut buffer = vec![];
			module_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_MODULE, &buffer)?;
		}

		if let Some(function_name_subsection) = self.functions {
			let mut buffer = vec![];
			function_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_FUNCTION, &buffer)?;
		}

		if let Some(local_name_subsection) = self.locals {
			let mut buffer = vec![];
			local_name_subsection.serialize(&mut buffer)?;
			serialize_subsection(wtr, NAME_TYPE_LOCAL, &buffer)?;
		}

		Ok(())
	}
}

/// The name of this module.
#[derive(Clone, Debug, PartialEq)]
pub struct ModuleNameSubsection {
	name: String,
}

impl ModuleNameSubsection {
	/// Create a new module name section with the specified name.
	pub fn new<S: Into<String>>(name: S) -> ModuleNameSubsection {
		ModuleNameSubsection { name: name.into() }
	}

	/// The name of this module.
	pub fn name(&self) -> &str {
		&self.name
	}

	/// The name of this module (mutable).
	pub fn name_mut(&mut self) -> &mut String {
		&mut self.name
	}
}

impl Serialize for ModuleNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.name.serialize(wtr)
	}
}

impl Deserialize for ModuleNameSubsection {
	type Error = Error;

	fn deserialize<R: io::Read>(rdr: &mut R) -> Result<ModuleNameSubsection, Error> {
		let name = String::deserialize(rdr)?;
		Ok(ModuleNameSubsection { name })
	}
}

/// The names of the functions in this module.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct FunctionNameSubsection {
	names: NameMap,
}

impl FunctionNameSubsection {
	/// A map from function indices to names.
	pub fn names(&self) -> &NameMap {
		&self.names
	}

	/// A map from function indices to names (mutable).
	pub fn names_mut(&mut self) -> &mut NameMap {
		&mut self.names
	}

	/// Deserialize names, making sure that all names correspond to functions.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<FunctionNameSubsection, Error> {
		let names = IndexMap::deserialize(module.functions_space(), rdr)?;
		Ok(FunctionNameSubsection { names })
	}
}

impl Serialize for FunctionNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.names.serialize(wtr)
	}
}

/// The names of the local variables in this module's functions.
#[derive(Clone, Debug, Default, PartialEq)]
pub struct LocalNameSubsection {
	local_names: IndexMap<NameMap>,
}

impl LocalNameSubsection {
	/// A map from function indices to a map from variables indices to names.
	pub fn local_names(&self) -> &IndexMap<NameMap> {
		&self.local_names
	}

	/// A map from function indices to a map from variables indices to names
	/// (mutable).
	pub fn local_names_mut(&mut self) -> &mut IndexMap<NameMap> {
		&mut self.local_names
	}

	/// Deserialize names, making sure that all names correspond to local
	/// variables.
	pub fn deserialize<R: io::Read>(
		module: &Module,
		rdr: &mut R,
	) -> Result<LocalNameSubsection, Error> {
		let max_entry_space = module.functions_space();

		let max_signature_args = module
			.type_section()
			.map(|ts|
				ts.types()
					.iter()
					.map(|x| { let Type::Function(ref func) = *x; func.params().len() })
					.max()
					.unwrap_or(0))
			.unwrap_or(0);

		let max_locals = module
			.code_section()
			.map(|cs|
				cs.bodies()
					.iter()
					.map(|f|
						f.locals()
						   .iter()
						   .map(|l| l.count() as usize)
						   .sum())
					.max()
					.unwrap_or(0))
			.unwrap_or(0);

		let max_space = max_signature_args + max_locals;

		let deserialize_locals = |_: u32, rdr: &mut R| IndexMap::deserialize(max_space, rdr);

		let local_names = IndexMap::deserialize_with(
			max_entry_space,
			&deserialize_locals,
			rdr,
		)?;
		Ok(LocalNameSubsection { local_names })
	}}

impl Serialize for LocalNameSubsection {
	type Error = Error;

	fn serialize<W: io::Write>(self, wtr: &mut W) -> Result<(), Error> {
		self.local_names.serialize(wtr)
	}
}

/// A map from indices to names.
pub type NameMap = IndexMap<String>;

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

	// A helper function for the tests. Serialize a section, deserialize it,
	// and make sure it matches the original.
	fn serialize_test(original: NameSection) -> Vec<u8> {
		let mut buffer = vec![];
		original
			.serialize(&mut buffer)
			.expect("serialize error");
		buffer
		// todo: add deserialization to this test
	}

	#[test]
	fn serialize_module_name() {
		let module_name_subsection = ModuleNameSubsection::new("my_mod");
		let original = NameSection::new(Some(module_name_subsection), None, None);
		serialize_test(original.clone());
	}

	#[test]
	fn serialize_function_names() {
		let mut function_name_subsection = FunctionNameSubsection::default();
		function_name_subsection.names_mut().insert(0, "hello_world".to_string());
		let name_section = NameSection::new(None, Some(function_name_subsection), None);
		serialize_test(name_section);
	}

	#[test]
	fn serialize_local_names() {
		let mut local_name_subsection = LocalNameSubsection::default();
		let mut locals = NameMap::default();
		locals.insert(0, "msg".to_string());
		local_name_subsection.local_names_mut().insert(0, locals);

		let name_section = NameSection::new(None, None, Some(local_name_subsection));
		serialize_test(name_section);
	}

	#[test]
	fn serialize_all_subsections() {
		let module_name_subsection = ModuleNameSubsection::new("ModuleNameSubsection");

		let mut function_name_subsection = FunctionNameSubsection::default();
		function_name_subsection.names_mut().insert(0, "foo".to_string());
		function_name_subsection.names_mut().insert(1, "bar".to_string());

		let mut local_name_subsection = LocalNameSubsection::default();
		let mut locals = NameMap::default();
		locals.insert(0, "msg1".to_string());
		locals.insert(1, "msg2".to_string());
		local_name_subsection.local_names_mut().insert(0, locals);

		let name_section = NameSection::new(Some(module_name_subsection), Some(function_name_subsection), Some(local_name_subsection));
		serialize_test(name_section);
	}

	#[test]
	fn deserialize_local_names() {
		let module = super::super::deserialize_file("./res/cases/v1/names_with_imports.wasm")
			.expect("Should be deserialized")
			.parse_names()
			.expect("Names to be parsed");

		let name_section = module.names_section().expect("name_section should be present");
		let local_names = name_section.locals().expect("local_name_section should be present");

		let locals = local_names.local_names().get(0).expect("entry #0 should be present");
		assert_eq!(
			locals.get(0).expect("entry #0 should be present"),
			"abc"
		);

		let locals = local_names.local_names().get(1).expect("entry #1 should be present");
		assert_eq!(
			locals.get(0).expect("entry #0 should be present"),
			"def"
		);
	}
}
<|endoftext|>