<commit_before>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate burst;

use super::address::Address;
use super::instruction::Instruction;
use std::fmt;

/// A representation of a Burst instruction.
#[derive(Debug)]
pub struct BurstInstruction {
    insn: burst::x86::Instruction,
}

impl Instruction for BurstInstruction {
    fn address(&self) -> Address {
        unimplemented!();
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn mnemonic(&self) -> &str {
        self.insn.operation.mnemonic()
    }

    fn is_call(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            CALL | CALLF => true,
            _ => false,
        }
    }

    fn is_local_conditional_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            JCXZ | JECXZ | JO | JNO | JB | JAE | JE | JNE | JBE | JA | JS | JNS | JPE | JPO
            | JL | JGE | JLE | JG | LOOP | LOOPE | LOOPNE => true,
            _ => false,
        }
    }

    fn is_local_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        self.is_local_conditional_jump() || match self.insn.operation {
            JMPF | JMP => true,
            _ => false,
        }
    }

    fn is_return(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            RETF | RETN => true,
            _ => false,
        }
    }

    fn target_address(&self) -> Option<Address> {
        let first_operand = &self.insn.operands[0];
        if first_operand.operand == burst::x86::OperandType::IMM {
            Some(Address::new(first_operand.immediate as u64))
        } else {
            None
        }
    }
}

impl fmt::Display for BurstInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data: [u8; 0] = [];
        let mut out = String::new();
        try!(burst::x86::format_instruction_string(
            &mut out, "%i %o", &data, 0, &self.insn,
        ));
        out.fmt(f)
    }
}

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

    #[test]
    fn test() {
        let code = &[0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00];

        if let Ok(insn) = burst::x86::disassemble_64(code, 0, code.len()) {
            let bi = BurstInstruction { insn };
            assert_eq!("push rbp", format!("{}", bi));
        }
    }
}
<commit_msg>burst: Use `?` instead of `try!`.<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate burst;

use super::address::Address;
use super::instruction::Instruction;
use std::fmt;

/// A representation of a Burst instruction.
#[derive(Debug)]
pub struct BurstInstruction {
    insn: burst::x86::Instruction,
}

impl Instruction for BurstInstruction {
    fn address(&self) -> Address {
        unimplemented!();
    }

    fn comment(&self) -> Option<String> {
        None
    }

    fn mnemonic(&self) -> &str {
        self.insn.operation.mnemonic()
    }

    fn is_call(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            CALL | CALLF => true,
            _ => false,
        }
    }

    fn is_local_conditional_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            JCXZ | JECXZ | JO | JNO | JB | JAE | JE | JNE | JBE | JA | JS | JNS | JPE | JPO
            | JL | JGE | JLE | JG | LOOP | LOOPE | LOOPNE => true,
            _ => false,
        }
    }

    fn is_local_jump(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        self.is_local_conditional_jump() || match self.insn.operation {
            JMPF | JMP => true,
            _ => false,
        }
    }

    fn is_return(&self) -> bool {
        use self::burst::x86::InstructionOperation::*;

        match self.insn.operation {
            RETF | RETN => true,
            _ => false,
        }
    }

    fn target_address(&self) -> Option<Address> {
        let first_operand = &self.insn.operands[0];
        if first_operand.operand == burst::x86::OperandType::IMM {
            Some(Address::new(first_operand.immediate as u64))
        } else {
            None
        }
    }
}

impl fmt::Display for BurstInstruction {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let data: [u8; 0] = [];
        let mut out = String::new();
        burst::x86::format_instruction_string(
            &mut out, "%i %o", &data, 0, &self.insn,
        )?;
        out.fmt(f)
    }
}

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

    #[test]
    fn test() {
        let code = &[0x55, 0x48, 0x8b, 0x05, 0xb8, 0x13, 0x00, 0x00];

        if let Ok(insn) = burst::x86::disassemble_64(code, 0, code.len()) {
            let bi = BurstInstruction { insn };
            assert_eq!("push rbp", format!("{}", bi));
        }
    }
}
<|endoftext|>


<commit_before>use dicom_core::value::C;
use snafu::Snafu;

pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error occurred when decoding,
    /// reported as a dynamic error value
    #[snafu(display("Error decoding pixel data"))]
    Custom {
        source: Box<dyn std::error::Error + Send + 'static>,
    },

    /// A custom error occurred when decoding,
    /// reported as a static message
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomMessage {
        message: &'static str,
    },

    /// Input pixel data is not encapsulated
    NotEncapsulated,

    /// A required attribute is missing from the DICOM
    #[snafu(display("Missing required attribute: {}", name))]
    MissingAttribute { name: &'static str },
}

/// Error conditions when encoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum EncodeError {
    /// A custom error when encoding fails
    #[snafu(display("Error encoding pixel data {}", message))]
    CustomEncodeError {
        message: &'static str,
    },

    /// Input pixel data is not native
    NotNative,

    /// Encoding is not implemented
    NotImplemented,
}

pub type DecodeResult<T, E = DecodeError> = Result<T, E>;

pub type EncodeResult<T, E = EncodeError> = Result<T, E>;

#[derive(Debug)]
pub struct RawPixelData {
    /// Either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated
    pub fragments: C<Vec<u8>>,

    /// The offset table for the fragments,
    /// or empty if there is none
    pub offset_table: C<u32>,
}

/// A DICOM object trait to be interpreted as pixel data.
///
/// This trait extends the concept of DICOM object
/// as defined in [`dicom_object`],
/// in order to retrieve important pieces of the object
/// for pixel data decoding into images or multi-dimensional arrays.
///
/// It is defined in this crate so that
/// transfer syntax implementers only have to depend on `dicom_encoding`.
///
/// [`dicom_object`]: https://docs.rs/dicom_object
pub trait PixelDataObject {
    /// Return the Rows attribute or None if it is not found
    fn rows(&self) -> Option<u16>;

    /// Return the Columns attribute or None if it is not found
    fn cols(&self) -> Option<u16>;

    /// Return the SamplesPerPixel attribute or None if it is not found
    fn samples_per_pixel(&self) -> Option<u16>;

    /// Return the BitsAllocated attribute or None if it is not set
    fn bits_allocated(&self) -> Option<u16>;

    /// Return the NumberOfFrames attribute or None if it is not set
    fn number_of_frames(&self) -> Option<u16>;

    /// Returns the number of fragments or None for native pixel data
    fn number_of_fragments(&self) -> Option<u32>;

    /// Return a specific encoded pixel fragment by index as Vec<u8>
    /// or None if no pixel data is found
    fn fragment(&self, fragment: usize) -> Option<Vec<u8>>;

    /// Should return either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated.
    /// Returns None if no pixel data is found
    fn raw_pixel_data(&self) -> Option<RawPixelData>;
}

/// Custom options when encoding pixel data into an encapsulated form.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct EncodeOptions {
    /// The quality of the output image as a number between 0 and 100,
    /// where 100 is the best quality that the encapsulated form can achieve
    /// and smaller values represent smaller data size
    /// with an increasingly higher error.
    /// It is ignored if the transfer syntax only supports lossless compression.
    /// If it does support lossless compression,
    /// it is expected that a quality of 100 results in a lossless encoding.
    ///
    /// If this option is not specified,
    /// the output quality is decided automatically by the underlying adapter.
    pub quality: Option<u8>,

    /// The amount of effort that the encoder may take to encode the pixel data,
    /// as a number between 0 and 100.
    /// If supported, higher values result in better compression,
    /// at the expense of more processing time.
    /// Encoders are not required to support this option.
    /// If this option is not specified,
    /// the actual effort is decided by the underlying adapter.
    pub effort: Option<u8>,
}

impl EncodeOptions {
    pub fn new() -> Self {
        Self::default()
    }
}

/// Trait object responsible for decoding and encoding
/// pixel data based on the Transfersyntax.
///
/// Every transfer syntax with encapsulated pixel data
/// should implement these methods.
///
pub trait PixelRWAdapter {
    /// Decode the given DICOM object
    /// containing encapsulated pixel data
    /// into native pixel data as a byte stream.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is encoded in accordance to the transfer syntax(es)
    /// supported by this adapter.
    /// A `NotEncapsulated` error is returned otherwise.
    ///
    /// The output is a sequence of native pixel values
    /// which follow the image properties of the given object.
    ///
    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()>;

    /// Encode a DICOM object's image into the format supported by this adapter,
    /// writing a byte stream of pixel data fragment values
    /// into the given destination.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is in a _native encoding_.
    /// A `NotNative` error is returned otherwise.
    ///
    /// It is possible that
    /// image encoding is not actually supported by this adapter,
    /// in which case a `NotImplemented` error is returned.
    /// Implementers leave the default method implementation
    /// for this behavior.
    #[allow(unused_variables)]
    fn encode(&self, src: &dyn PixelDataObject, options: EncodeOptions, dst: &mut Vec<u8>) -> EncodeResult<()> {
        Err(EncodeError::NotImplemented)
    }
}

/// Alias type for a dynamically dispatched data adapter.
pub type DynPixelRWAdapter = Box<dyn PixelRWAdapter + Send + Sync>;

/// An immaterial type representing an adapter which is never required.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverPixelAdapter {}

impl PixelRWAdapter for NeverPixelAdapter {
    fn decode(&self, _src: &dyn PixelDataObject, _dst: &mut Vec<u8>) -> DecodeResult<()> {
        unreachable!();
    }

    fn encode(&self, _src: &dyn PixelDataObject, _options: EncodeOptions, _dst: &mut Vec<u8>) -> EncodeResult<()> {
        unreachable!();
    }
}
<commit_msg>[encoding] Add root documentation to adapters module<commit_after>//! Module for built-in pixel data adapters.

use dicom_core::value::C;
use snafu::Snafu;

pub mod rle_lossless;

/// Error conditions when decoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum DecodeError {
    /// A custom error occurred when decoding,
    /// reported as a dynamic error value
    #[snafu(display("Error decoding pixel data"))]
    Custom {
        source: Box<dyn std::error::Error + Send + 'static>,
    },

    /// A custom error occurred when decoding,
    /// reported as a static message
    #[snafu(display("Error decoding pixel data: {}", message))]
    CustomMessage {
        message: &'static str,
    },

    /// Input pixel data is not encapsulated
    NotEncapsulated,

    /// A required attribute is missing from the DICOM
    #[snafu(display("Missing required attribute: {}", name))]
    MissingAttribute { name: &'static str },
}

/// Error conditions when encoding pixel data.
#[derive(Debug, Snafu)]
#[non_exhaustive]
pub enum EncodeError {
    /// A custom error when encoding fails
    #[snafu(display("Error encoding pixel data {}", message))]
    CustomEncodeError {
        message: &'static str,
    },

    /// Input pixel data is not native
    NotNative,

    /// Encoding is not implemented
    NotImplemented,
}

pub type DecodeResult<T, E = DecodeError> = Result<T, E>;

pub type EncodeResult<T, E = EncodeError> = Result<T, E>;

#[derive(Debug)]
pub struct RawPixelData {
    /// Either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated
    pub fragments: C<Vec<u8>>,

    /// The offset table for the fragments,
    /// or empty if there is none
    pub offset_table: C<u32>,
}

/// A DICOM object trait to be interpreted as pixel data.
///
/// This trait extends the concept of DICOM object
/// as defined in [`dicom_object`],
/// in order to retrieve important pieces of the object
/// for pixel data decoding into images or multi-dimensional arrays.
///
/// It is defined in this crate so that
/// transfer syntax implementers only have to depend on `dicom_encoding`.
///
/// [`dicom_object`]: https://docs.rs/dicom_object
pub trait PixelDataObject {
    /// Return the Rows attribute or None if it is not found
    fn rows(&self) -> Option<u16>;

    /// Return the Columns attribute or None if it is not found
    fn cols(&self) -> Option<u16>;

    /// Return the SamplesPerPixel attribute or None if it is not found
    fn samples_per_pixel(&self) -> Option<u16>;

    /// Return the BitsAllocated attribute or None if it is not set
    fn bits_allocated(&self) -> Option<u16>;

    /// Return the NumberOfFrames attribute or None if it is not set
    fn number_of_frames(&self) -> Option<u16>;

    /// Returns the number of fragments or None for native pixel data
    fn number_of_fragments(&self) -> Option<u32>;

    /// Return a specific encoded pixel fragment by index as Vec<u8>
    /// or None if no pixel data is found
    fn fragment(&self, fragment: usize) -> Option<Vec<u8>>;

    /// Should return either a byte slice/vector if native pixel data
    /// or byte fragments if encapsulated.
    /// Returns None if no pixel data is found
    fn raw_pixel_data(&self) -> Option<RawPixelData>;
}

/// Custom options when encoding pixel data into an encapsulated form.
#[derive(Debug, Default, Clone)]
#[non_exhaustive]
pub struct EncodeOptions {
    /// The quality of the output image as a number between 0 and 100,
    /// where 100 is the best quality that the encapsulated form can achieve
    /// and smaller values represent smaller data size
    /// with an increasingly higher error.
    /// It is ignored if the transfer syntax only supports lossless compression.
    /// If it does support lossless compression,
    /// it is expected that a quality of 100 results in a lossless encoding.
    ///
    /// If this option is not specified,
    /// the output quality is decided automatically by the underlying adapter.
    pub quality: Option<u8>,

    /// The amount of effort that the encoder may take to encode the pixel data,
    /// as a number between 0 and 100.
    /// If supported, higher values result in better compression,
    /// at the expense of more processing time.
    /// Encoders are not required to support this option.
    /// If this option is not specified,
    /// the actual effort is decided by the underlying adapter.
    pub effort: Option<u8>,
}

impl EncodeOptions {
    pub fn new() -> Self {
        Self::default()
    }
}

/// Trait object responsible for decoding and encoding
/// pixel data based on the Transfersyntax.
///
/// Every transfer syntax with encapsulated pixel data
/// should implement these methods.
///
pub trait PixelRWAdapter {
    /// Decode the given DICOM object
    /// containing encapsulated pixel data
    /// into native pixel data as a byte stream.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is encoded in accordance to the transfer syntax(es)
    /// supported by this adapter.
    /// A `NotEncapsulated` error is returned otherwise.
    ///
    /// The output is a sequence of native pixel values
    /// which follow the image properties of the given object.
    ///
    fn decode(&self, src: &dyn PixelDataObject, dst: &mut Vec<u8>) -> DecodeResult<()>;

    /// Encode a DICOM object's image into the format supported by this adapter,
    /// writing a byte stream of pixel data fragment values
    /// into the given destination.
    ///
    /// It is a necessary precondition that the object's pixel data
    /// is in a _native encoding_.
    /// A `NotNative` error is returned otherwise.
    ///
    /// It is possible that
    /// image encoding is not actually supported by this adapter,
    /// in which case a `NotImplemented` error is returned.
    /// Implementers leave the default method implementation
    /// for this behavior.
    #[allow(unused_variables)]
    fn encode(&self, src: &dyn PixelDataObject, options: EncodeOptions, dst: &mut Vec<u8>) -> EncodeResult<()> {
        Err(EncodeError::NotImplemented)
    }
}

/// Alias type for a dynamically dispatched data adapter.
pub type DynPixelRWAdapter = Box<dyn PixelRWAdapter + Send + Sync>;

/// An immaterial type representing an adapter which is never required.
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)]
pub enum NeverPixelAdapter {}

impl PixelRWAdapter for NeverPixelAdapter {
    fn decode(&self, _src: &dyn PixelDataObject, _dst: &mut Vec<u8>) -> DecodeResult<()> {
        unreachable!();
    }

    fn encode(&self, _src: &dyn PixelDataObject, _options: EncodeOptions, _dst: &mut Vec<u8>) -> EncodeResult<()> {
        unreachable!();
    }
}
<|endoftext|>


<commit_before>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)

        // (160, 160, 160)

        // (180, 180, 180)

        (199, 199, 199)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (40, 44, 52) // soft grey
        (11, 16, 39) // deep blue
                     // (35, 35, 35)    // black
    }

    pub fn title_color() -> (u8, u8, u8) {
        Self::default_bg_color()
    }

    pub fn title_bg_color() -> (u8, u8, u8) {
        Self::default_color()
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        let c = Self::default_bg_color();

        let diff_r = 20 + 15;
        let diff_g = 20 + 15;
        let diff_b = 20 + 50;

        (
            c.0.saturating_add(diff_r),
            c.1.saturating_add(diff_g),
            c.2.saturating_add(diff_b),
        )
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        (0, 0, 0)
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    /// Ignore this CodepointInfo if set to false.
    pub used: bool, // rename into ignore ?
    /// The CodepointInfo is some part metadata.

    /// When set to true offset must be set to None
    pub metadata: bool, // TODO(ceg): prefer enum use enum { Normal, Eof, ... }
    /// The real codepoint found on storage
    pub cp: char,
    /// The codepoint to display
    pub displayed_cp: char,
    /// Storage offset
    pub offset: Option<u64>,
    /// Storage size in bytes
    pub size: usize,
    /// Hints for render
    pub skip_render: bool,
    /// Style to apply when rendering
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<commit_msg>work on colors<commit_after>/// TextStyle holds the displayed attributes flags.
#[derive(Debug, Default, Hash, Clone, Copy, Eq, PartialEq)]
pub struct TextStyle {
    /// The character should blink.
    pub is_blinking: bool,
    /// The character is a part of a selection.
    pub is_selected: bool,
    /// The fg/bg attributes are reversed (used to simulate cursors/marks).
    pub is_inverse: bool,
    /// The character should be displayed as bold.
    pub is_bold: bool,
    /// The character should be displayed in italic.
    pub is_italic: bool,
    /// rbg tuple for foreground color
    pub color: (u8, u8, u8), // RGB
    /// rbg tuple for background color
    pub bg_color: (u8, u8, u8), // RGB
}

impl TextStyle {
    pub fn new() -> Self {
        TextStyle {
            is_blinking: false,
            is_selected: false,
            is_inverse: false,
            is_bold: false,
            is_italic: false,
            color: Self::default_color(),
            bg_color: Self::default_bg_color(),
        }
    }

    pub fn default_color() -> (u8, u8, u8) {
        // (192, 192, 192) // White
        // (128, 128, 128)    // Gray
        //(177, 177, 177)

        // (160, 160, 160)

        // (180, 180, 180)

        (199, 199, 199)
    }

    pub fn default_bg_color() -> (u8, u8, u8) {
        // (35, 35, 35) // black
        // (0, 0, 48)
        // (38, 41, 44)
        // (40, 44, 52) // soft grey
        (11, 16, 39) // deep blue
    }

    pub fn title_color() -> (u8, u8, u8) {
        Self::default_bg_color()
    }

    pub fn title_bg_color() -> (u8, u8, u8) {
        Self::default_color()
    }

    pub fn default_selected_bg_color() -> (u8, u8, u8) {
        let c = Self::default_bg_color();
        let add = 20;
        (c.0 + add, c.1 + add, c.2 + add)
    }

    pub fn default_mark_line_bg_color() -> (u8, u8, u8) {
        Self::default_selected_bg_color()
    }
}

/// A CodepointInfo contains displayed character attributes.

/// The displayed screen is composed of LineCell(s), that contain CodepointInfo(s).
#[derive(Hash, Default, Debug, Clone, Copy, Eq, PartialEq)]
pub struct CodepointInfo {
    /// Ignore this CodepointInfo if set to false.
    pub used: bool, // rename into ignore ?
    /// The CodepointInfo is some part metadata.

    /// When set to true offset must be set to None
    pub metadata: bool, // TODO(ceg): prefer enum use enum { Normal, Eof, ... }
    /// The real codepoint found on storage
    pub cp: char,
    /// The codepoint to display
    pub displayed_cp: char,
    /// Storage offset
    pub offset: Option<u64>,
    /// Storage size in bytes
    pub size: usize,
    /// Hints for render
    pub skip_render: bool,
    /// Style to apply when rendering
    pub style: TextStyle,
}

impl CodepointInfo {
    pub fn new() -> Self {
        CodepointInfo {
            used: false,
            metadata: true,
            cp: ' ',
            displayed_cp: ' ',
            offset: None,
            size: 0,
            skip_render: false,
            //
            style: TextStyle::new(),
        }
    }
}

/*
Logical Color	Terminal Color	RGB Value Used by SGD
Black	0 0 0
Light_red	255 0 0
Light_green	0 255 0
Yellow	255 255 0
Light_blue	0 0 255
Light_magenta	255 0 255
Light_cyan	    0 255 255
High_white	    255 255 255
Gray	    128 128 128
Red	    128 0 0
Green	0 128 0
Brown	128 128 0
Blue	0 0 128
Magenta	128 0 128
Cyan	0 128 128
White	192 192 192
*/
<|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/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

#[cfg(feature = "gecko")]
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{SourceLocation, CowRcStr};
use error_reporting::ContextualParseError;
#[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors;
#[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::font_language_override;
use selectors::parser::SelectorParseError;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    #[css(function)]
    Local(FamilyName),
}

impl OneOrMoreSeparated for Source {
    type S = Comma;
}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        self.url.to_css(dest)
    }
}

/// A font-display value for a @font-face rule.
/// The font-display descriptor determines how a font face is displayed based
/// on whether and when it is downloaded and ready to use.
define_css_keyword_enum!(FontDisplay:
                         "auto" => Auto,
                         "block" => Block,
                         "swap" => Swap,
                         "fallback" => Fallback,
                         "optional" => Optional);
add_impls_for_keyword_enum!(FontDisplay);

/// A font-weight value for a @font-face rule.
/// The font-weight CSS property specifies the weight or boldness of the font.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum FontWeight {
    /// Numeric font weights for fonts that provide more than just normal and bold.
    Weight(font_weight::T),
    /// Normal font weight. Same as 400.
    Normal,
    /// Bold font weight. Same as 700.
    Bold,
}

#[cfg(feature = "gecko")]
impl Parse for FontWeight {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
        -> Result<FontWeight, ParseError<'i>> {
        let result = input.try(|input| {
            let ident = input.expect_ident().map_err(|_| ())?;
            match_ignore_ascii_case! { &ident,
                "normal" => Ok(FontWeight::Normal),
                "bold" => Ok(FontWeight::Bold),
                _ => Err(())
            }
        });
        result.or_else(|_| {
            font_weight::T::from_int(input.expect_integer()?)
                .map(FontWeight::Weight)
                .map_err(|()| StyleParseError::UnspecifiedError.into())
        })
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, location: SourceLocation)
    -> FontFaceRuleData {
    let mut rule = FontFaceRuleData::empty();
    rule.source_location = location;
    {
        let parser = FontFaceRuleParser {
            context: context,
            rule: &mut rule,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(err) = declaration {
                let pos = err.span.start;
                let error = ContextualParseError::UnsupportedFontFaceDescriptor(
                    iter.input.slice(err.span), err.error);
                log_css_error(iter.input, pos, error, context);
            }
        }
    }
    rule
}

/// A @font-face rule that is known to have font-family and src declarations.
#[cfg(feature = "servo")]
pub struct FontFace<'a>(&'a FontFaceRuleData);

/// A list of effective sources that we send over through IPC to the font cache.
#[cfg(feature = "servo")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

#[cfg(feature = "servo")]
impl<'a> FontFace<'a> {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources().iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

#[cfg(feature = "servo")]
impl Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut FontFaceRuleData,
}

/// Default methods reject all at rules.
impl<'a, 'b, 'i> AtRuleParser<'i> for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
    type Error = SelectorParseError<'i, StyleParseError<'i>>;
}

impl Parse for Source {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Source, ParseError<'i>> {
        if input.try(|input| input.expect_function_matching("local")).is_ok() {
            return input.parse_nested_block(|input| {
                FamilyName::parse(context, input)
            }).map(Source::Local)
        }

        let url = SpecifiedUrl::parse(context, input)?;

        // Parsing optional format()
        let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
            input.parse_nested_block(|input| {
                input.parse_comma_separated(|input| {
                    Ok(input.expect_string()?.as_ref().to_owned())
                })
            })?
        } else {
            vec![]
        };

        Ok(Source::Url(UrlSource {
            url: url,
            format_hints: format_hints,
        }))
    }
}

macro_rules! font_face_descriptors_common {
    (
        $( #[$doc: meta] $name: tt $ident: ident / $gecko_ident: ident: $ty: ty, )*
    ) => {
        /// Data inside a `@font-face` rule.
        ///
        /// https://drafts.csswg.org/css-fonts/#font-face-rule
        #[derive(Clone, Debug, PartialEq, Eq)]
        pub struct FontFaceRuleData {
            $(
                #[$doc]
                pub $ident: Option<$ty>,
            )*
            /// Line and column of the @font-face rule source code.
            pub source_location: SourceLocation,
        }

        impl FontFaceRuleData {
            fn empty() -> Self {
                FontFaceRuleData {
                    $(
                        $ident: None,
                    )*
                    source_location: SourceLocation {
                        line: 0,
                        column: 0,
                    },
                }
            }

            /// Convert to Gecko types
            #[cfg(feature = "gecko")]
            pub fn set_descriptors(self, descriptors: &mut CSSFontFaceDescriptors) {
                $(
                    if let Some(value) = self.$ident {
                        descriptors.$gecko_ident.set_from(value)
                    }
                )*
                // Leave unset descriptors to eCSSUnit_Null,
                // FontFaceSet::FindOrCreateUserFontEntryFromFontFace does the defaulting
                // to initial values.
            }
        }

        impl ToCssWithGuard for FontFaceRuleData {
            // Serialization of FontFaceRule is not specced.
            fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
            where W: fmt::Write {
                dest.write_str("@font-face {\n")?;
                $(
                    if let Some(ref value) = self.$ident {
                        dest.write_str(concat!("  ", $name, ": "))?;
                        ToCss::to_css(value, dest)?;
                        dest.write_str(";\n")?;
                    }
                )*
                dest.write_str("}")
            }
        }

       impl<'a, 'b, 'i> DeclarationParser<'i> for FontFaceRuleParser<'a, 'b> {
           type Declaration = ();
           type Error = SelectorParseError<'i, StyleParseError<'i>>;

           fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
                              -> Result<(), ParseError<'i>> {
                match_ignore_ascii_case! { &*name,
                    $(
                        $name => {
                            // DeclarationParser also calls parse_entirely
                            // so we’d normally not need to,
                            // but in this case we do because we set the value as a side effect
                            // rather than returning it.
                            let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
                            self.rule.$ident = Some(value)
                        }
                    )*
                    _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
                }
                Ok(())
            }
        }
    }
}

macro_rules! font_face_descriptors {
    (
        mandatory descriptors = [
            $( #[$m_doc: meta] $m_name: tt $m_ident: ident / $m_gecko_ident: ident: $m_ty: ty, )*
        ]
        optional descriptors = [
            $( #[$o_doc: meta] $o_name: tt $o_ident: ident / $o_gecko_ident: ident: $o_ty: ty =
                $o_initial: expr, )*
        ]
    ) => {
        font_face_descriptors_common! {
            $( #[$m_doc] $m_name $m_ident / $m_gecko_ident: $m_ty, )*
            $( #[$o_doc] $o_name $o_ident / $o_gecko_ident: $o_ty, )*
        }

        impl FontFaceRuleData {
            /// Per https://github.com/w3c/csswg-drafts/issues/1133 an @font-face rule
            /// is valid as far as the CSS parser is concerned even if it doesn’t have
            /// a font-family or src declaration.
            ///
            /// However both are required for the rule to represent an actual font face.
            #[cfg(feature = "servo")]
            pub fn font_face(&self) -> Option<FontFace> {
                if $( self.$m_ident.is_some() )&&* {
                    Some(FontFace(self))
                } else {
                    None
                }
            }
        }

        #[cfg(feature = "servo")]
        impl<'a> FontFace<'a> {
            $(
                #[$m_doc]
                pub fn $m_ident(&self) -> &$m_ty {
                    self.0 .$m_ident.as_ref().unwrap()
                }
            )*
            $(
                #[$o_doc]
                pub fn $o_ident(&self) -> $o_ty {
                    if let Some(ref value) = self.0 .$o_ident {
                        value.clone()
                    } else {
                        $o_initial
                    }
                }
            )*
        }
    }
}

/// css-name rust_identifier: Type = initial_value,
#[cfg(feature = "gecko")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The name of this font face
        "font-family" family / mFamily: FamilyName,

        /// The alternative sources for this font face.
        "src" sources / mSrc: Vec<Source>,
    ]
    optional descriptors = [
        /// The style of this font face
        "font-style" style / mStyle: font_style::T = font_style::T::normal,

        /// The weight of this font face
        "font-weight" weight / mWeight: FontWeight = FontWeight::Normal,

        /// The stretch of this font face
        "font-stretch" stretch / mStretch: font_stretch::T = font_stretch::T::normal,

        /// The display of this font face
        "font-display" display / mDisplay: FontDisplay = FontDisplay::Auto,

        /// The ranges of code points outside of which this font face should not be used.
        "unicode-range" unicode_range / mUnicodeRange: Vec<UnicodeRange> = vec![
            UnicodeRange { start: 0, end: 0x10FFFF }
        ],

        /// The feature settings of this font face.
        "font-feature-settings" feature_settings / mFontFeatureSettings: font_feature_settings::T = {
            font_feature_settings::T::Normal
        },

        /// The language override of this font face.
        "font-language-override" language_override / mFontLanguageOverride: font_language_override::SpecifiedValue = {
            font_language_override::SpecifiedValue::Normal
        },
    ]
}

#[cfg(feature = "servo")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The name of this font face
        "font-family" family / mFamily: FamilyName,

        /// The alternative sources for this font face.
        "src" sources / mSrc: Vec<Source>,
    ]
    optional descriptors = [
    ]
}
<commit_msg>Auto merge of #17877 - canaltinova:font-face-refactoring, r=jdm<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/. */

//! The [`@font-face`][ff] at-rule.
//!
//! [ff]: https://drafts.csswg.org/css-fonts/#at-font-face-rule

#![deny(missing_docs)]

#[cfg(feature = "gecko")]
use computed_values::{font_feature_settings, font_stretch, font_style, font_weight};
use computed_values::font_family::FamilyName;
use cssparser::{AtRuleParser, DeclarationListParser, DeclarationParser, Parser};
use cssparser::{SourceLocation, CowRcStr};
use error_reporting::ContextualParseError;
#[cfg(feature = "gecko")] use gecko_bindings::structs::CSSFontFaceDescriptors;
#[cfg(feature = "gecko")] use cssparser::UnicodeRange;
use parser::{ParserContext, log_css_error, Parse};
#[cfg(feature = "gecko")]
use properties::longhands::font_language_override;
use selectors::parser::SelectorParseError;
use shared_lock::{SharedRwLockReadGuard, ToCssWithGuard};
use std::fmt;
use style_traits::{Comma, OneOrMoreSeparated, ParseError, StyleParseError, ToCss};
use values::specified::url::SpecifiedUrl;

/// A source for a font-face rule.
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum Source {
    /// A `url()` source.
    Url(UrlSource),
    /// A `local()` source.
    #[css(function)]
    Local(FamilyName),
}

impl OneOrMoreSeparated for Source {
    type S = Comma;
}

/// A `UrlSource` represents a font-face source that has been specified with a
/// `url()` function.
///
/// https://drafts.csswg.org/css-fonts/#src-desc
#[derive(Clone, Debug, PartialEq, Eq)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct UrlSource {
    /// The specified url.
    pub url: SpecifiedUrl,
    /// The format hints specified with the `format()` function.
    pub format_hints: Vec<String>,
}

impl ToCss for UrlSource {
    fn to_css<W>(&self, dest: &mut W) -> fmt::Result
        where W: fmt::Write,
    {
        self.url.to_css(dest)
    }
}

/// A font-display value for a @font-face rule.
/// The font-display descriptor determines how a font face is displayed based
/// on whether and when it is downloaded and ready to use.
define_css_keyword_enum!(FontDisplay:
                         "auto" => Auto,
                         "block" => Block,
                         "swap" => Swap,
                         "fallback" => Fallback,
                         "optional" => Optional);
add_impls_for_keyword_enum!(FontDisplay);

/// A font-weight value for a @font-face rule.
/// The font-weight CSS property specifies the weight or boldness of the font.
#[cfg(feature = "gecko")]
#[derive(Clone, Debug, Eq, PartialEq, ToCss)]
pub enum FontWeight {
    /// Numeric font weights for fonts that provide more than just normal and bold.
    Weight(font_weight::T),
    /// Normal font weight. Same as 400.
    Normal,
    /// Bold font weight. Same as 700.
    Bold,
}

#[cfg(feature = "gecko")]
impl Parse for FontWeight {
    fn parse<'i, 't>(_: &ParserContext, input: &mut Parser<'i, 't>)
        -> Result<FontWeight, ParseError<'i>> {
        let result = input.try(|input| {
            let ident = input.expect_ident().map_err(|_| ())?;
            match_ignore_ascii_case! { &ident,
                "normal" => Ok(FontWeight::Normal),
                "bold" => Ok(FontWeight::Bold),
                _ => Err(())
            }
        });
        result.or_else(|_| {
            font_weight::T::from_int(input.expect_integer()?)
                .map(FontWeight::Weight)
                .map_err(|()| StyleParseError::UnspecifiedError.into())
        })
    }
}

/// Parse the block inside a `@font-face` rule.
///
/// Note that the prelude parsing code lives in the `stylesheets` module.
pub fn parse_font_face_block(context: &ParserContext, input: &mut Parser, location: SourceLocation)
    -> FontFaceRuleData {
    let mut rule = FontFaceRuleData::empty(location);
    {
        let parser = FontFaceRuleParser {
            context: context,
            rule: &mut rule,
        };
        let mut iter = DeclarationListParser::new(input, parser);
        while let Some(declaration) = iter.next() {
            if let Err(err) = declaration {
                let pos = err.span.start;
                let error = ContextualParseError::UnsupportedFontFaceDescriptor(
                    iter.input.slice(err.span), err.error);
                log_css_error(iter.input, pos, error, context);
            }
        }
    }
    rule
}

/// A @font-face rule that is known to have font-family and src declarations.
#[cfg(feature = "servo")]
pub struct FontFace<'a>(&'a FontFaceRuleData);

/// A list of effective sources that we send over through IPC to the font cache.
#[cfg(feature = "servo")]
#[derive(Clone, Debug)]
#[cfg_attr(feature = "servo", derive(Deserialize, Serialize))]
pub struct EffectiveSources(Vec<Source>);

#[cfg(feature = "servo")]
impl<'a> FontFace<'a> {
    /// Returns the list of effective sources for that font-face, that is the
    /// sources which don't list any format hint, or the ones which list at
    /// least "truetype" or "opentype".
    pub fn effective_sources(&self) -> EffectiveSources {
        EffectiveSources(self.sources().iter().rev().filter(|source| {
            if let Source::Url(ref url_source) = **source {
                let hints = &url_source.format_hints;
                // We support only opentype fonts and truetype is an alias for
                // that format. Sources without format hints need to be
                // downloaded in case we support them.
                hints.is_empty() || hints.iter().any(|hint| {
                    hint == "truetype" || hint == "opentype" || hint == "woff"
                })
            } else {
                true
            }
        }).cloned().collect())
    }
}

#[cfg(feature = "servo")]
impl Iterator for EffectiveSources {
    type Item = Source;
    fn next(&mut self) -> Option<Source> {
        self.0.pop()
    }
}

struct FontFaceRuleParser<'a, 'b: 'a> {
    context: &'a ParserContext<'b>,
    rule: &'a mut FontFaceRuleData,
}

/// Default methods reject all at rules.
impl<'a, 'b, 'i> AtRuleParser<'i> for FontFaceRuleParser<'a, 'b> {
    type Prelude = ();
    type AtRule = ();
    type Error = SelectorParseError<'i, StyleParseError<'i>>;
}

impl Parse for Source {
    fn parse<'i, 't>(context: &ParserContext, input: &mut Parser<'i, 't>)
                     -> Result<Source, ParseError<'i>> {
        if input.try(|input| input.expect_function_matching("local")).is_ok() {
            return input.parse_nested_block(|input| {
                FamilyName::parse(context, input)
            }).map(Source::Local)
        }

        let url = SpecifiedUrl::parse(context, input)?;

        // Parsing optional format()
        let format_hints = if input.try(|input| input.expect_function_matching("format")).is_ok() {
            input.parse_nested_block(|input| {
                input.parse_comma_separated(|input| {
                    Ok(input.expect_string()?.as_ref().to_owned())
                })
            })?
        } else {
            vec![]
        };

        Ok(Source::Url(UrlSource {
            url: url,
            format_hints: format_hints,
        }))
    }
}

macro_rules! font_face_descriptors_common {
    (
        $( #[$doc: meta] $name: tt $ident: ident / $gecko_ident: ident: $ty: ty, )*
    ) => {
        /// Data inside a `@font-face` rule.
        ///
        /// https://drafts.csswg.org/css-fonts/#font-face-rule
        #[derive(Clone, Debug, PartialEq, Eq)]
        pub struct FontFaceRuleData {
            $(
                #[$doc]
                pub $ident: Option<$ty>,
            )*
            /// Line and column of the @font-face rule source code.
            pub source_location: SourceLocation,
        }

        impl FontFaceRuleData {
            fn empty(location: SourceLocation) -> Self {
                FontFaceRuleData {
                    $(
                        $ident: None,
                    )*
                    source_location: location,
                }
            }

            /// Convert to Gecko types
            #[cfg(feature = "gecko")]
            pub fn set_descriptors(self, descriptors: &mut CSSFontFaceDescriptors) {
                $(
                    if let Some(value) = self.$ident {
                        descriptors.$gecko_ident.set_from(value)
                    }
                )*
                // Leave unset descriptors to eCSSUnit_Null,
                // FontFaceSet::FindOrCreateUserFontEntryFromFontFace does the defaulting
                // to initial values.
            }
        }

        impl ToCssWithGuard for FontFaceRuleData {
            // Serialization of FontFaceRule is not specced.
            fn to_css<W>(&self, _guard: &SharedRwLockReadGuard, dest: &mut W) -> fmt::Result
            where W: fmt::Write {
                dest.write_str("@font-face {\n")?;
                $(
                    if let Some(ref value) = self.$ident {
                        dest.write_str(concat!("  ", $name, ": "))?;
                        ToCss::to_css(value, dest)?;
                        dest.write_str(";\n")?;
                    }
                )*
                dest.write_str("}")
            }
        }

       impl<'a, 'b, 'i> DeclarationParser<'i> for FontFaceRuleParser<'a, 'b> {
           type Declaration = ();
           type Error = SelectorParseError<'i, StyleParseError<'i>>;

           fn parse_value<'t>(&mut self, name: CowRcStr<'i>, input: &mut Parser<'i, 't>)
                              -> Result<(), ParseError<'i>> {
                match_ignore_ascii_case! { &*name,
                    $(
                        $name => {
                            // DeclarationParser also calls parse_entirely
                            // so we’d normally not need to,
                            // but in this case we do because we set the value as a side effect
                            // rather than returning it.
                            let value = input.parse_entirely(|i| Parse::parse(self.context, i))?;
                            self.rule.$ident = Some(value)
                        }
                    )*
                    _ => return Err(SelectorParseError::UnexpectedIdent(name.clone()).into())
                }
                Ok(())
            }
        }
    }
}

macro_rules! font_face_descriptors {
    (
        mandatory descriptors = [
            $( #[$m_doc: meta] $m_name: tt $m_ident: ident / $m_gecko_ident: ident: $m_ty: ty, )*
        ]
        optional descriptors = [
            $( #[$o_doc: meta] $o_name: tt $o_ident: ident / $o_gecko_ident: ident: $o_ty: ty =
                $o_initial: expr, )*
        ]
    ) => {
        font_face_descriptors_common! {
            $( #[$m_doc] $m_name $m_ident / $m_gecko_ident: $m_ty, )*
            $( #[$o_doc] $o_name $o_ident / $o_gecko_ident: $o_ty, )*
        }

        impl FontFaceRuleData {
            /// Per https://github.com/w3c/csswg-drafts/issues/1133 an @font-face rule
            /// is valid as far as the CSS parser is concerned even if it doesn’t have
            /// a font-family or src declaration.
            ///
            /// However both are required for the rule to represent an actual font face.
            #[cfg(feature = "servo")]
            pub fn font_face(&self) -> Option<FontFace> {
                if $( self.$m_ident.is_some() )&&* {
                    Some(FontFace(self))
                } else {
                    None
                }
            }
        }

        #[cfg(feature = "servo")]
        impl<'a> FontFace<'a> {
            $(
                #[$m_doc]
                pub fn $m_ident(&self) -> &$m_ty {
                    self.0 .$m_ident.as_ref().unwrap()
                }
            )*
            $(
                #[$o_doc]
                pub fn $o_ident(&self) -> $o_ty {
                    if let Some(ref value) = self.0 .$o_ident {
                        value.clone()
                    } else {
                        $o_initial
                    }
                }
            )*
        }
    }
}

/// css-name rust_identifier: Type = initial_value,
#[cfg(feature = "gecko")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The name of this font face
        "font-family" family / mFamily: FamilyName,

        /// The alternative sources for this font face.
        "src" sources / mSrc: Vec<Source>,
    ]
    optional descriptors = [
        /// The style of this font face
        "font-style" style / mStyle: font_style::T = font_style::T::normal,

        /// The weight of this font face
        "font-weight" weight / mWeight: FontWeight = FontWeight::Normal,

        /// The stretch of this font face
        "font-stretch" stretch / mStretch: font_stretch::T = font_stretch::T::normal,

        /// The display of this font face
        "font-display" display / mDisplay: FontDisplay = FontDisplay::Auto,

        /// The ranges of code points outside of which this font face should not be used.
        "unicode-range" unicode_range / mUnicodeRange: Vec<UnicodeRange> = vec![
            UnicodeRange { start: 0, end: 0x10FFFF }
        ],

        /// The feature settings of this font face.
        "font-feature-settings" feature_settings / mFontFeatureSettings: font_feature_settings::T = {
            font_feature_settings::T::Normal
        },

        /// The language override of this font face.
        "font-language-override" language_override / mFontLanguageOverride: font_language_override::SpecifiedValue = {
            font_language_override::SpecifiedValue::Normal
        },
    ]
}

#[cfg(feature = "servo")]
font_face_descriptors! {
    mandatory descriptors = [
        /// The name of this font face
        "font-family" family / mFamily: FamilyName,

        /// The alternative sources for this font face.
        "src" sources / mSrc: Vec<Source>,
    ]
    optional descriptors = [
    ]
}
<|endoftext|>


<commit_before>
#[derive(Debug)]
/// nccl Error type.
pub enum Error {
    KeyNotFound,
    IndentationError,
    NameError,
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "An error has ocurred: {:?}", self)
    }
}

#[allow(unreachable_patterns)]
impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::KeyNotFound => "Key not found.",
            Error::IndentationError => "Incorrect indentation: Not 4 spaces.",
            Error::NameError => "Schema not found.",
            _ => "Unknown error."
        }
    }
}

<commit_msg>remove unreachable pattern<commit_after>
#[derive(Debug)]
/// nccl Error type.
pub enum Error {
    KeyNotFound,
    IndentationError,
    NameError,
}

impl ::std::fmt::Display for Error {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "An error has ocurred: {:?}", self)
    }
}

impl ::std::error::Error for Error {
    fn description(&self) -> &str {
        match *self {
            Error::KeyNotFound => "Key not found.",
            Error::IndentationError => "Incorrect indentation: Not 4 spaces.",
            Error::NameError => "Schema not found.",
        }
    }
}

<|endoftext|>


<commit_before>use std::io::Result;

fn main() -> Result<()> {
    let mut args = std::env::args().skip(1);
    let key   = args.next().unwrap_or_default();
    let value = args.next().unwrap_or_default();

    write_db(key, value)?;

    Ok(())
}

fn write_db(key: String, value: String) -> Result<()> {
    return std::fs::write("kv.db", format!("{}={}", key, value));
}
<commit_msg>well whatever<commit_after>use std::io::Result as R;
type Map = std::collections::HashMap<String, String>;

fn main() -> R<()> {
    let mut args = std::env::args().skip(1);
    let key   = args.next().unwrap_or_default();
    let value = args.next().unwrap_or_default();

    let mut db = Database::create()?;
    db.insert(key, value);
    db.write()?;

    Ok(())
}

struct Database {
    map: Map
}

impl Database {
    fn create() -> R<Database> {
        let contents = std::fs::read_to_string("kv.db")?;
        let mut map = Map::new();
        for line in contents.lines() {
            let mut kv = line.split("=");
            let k = kv.next().unwrap_or_default().to_string();
            let v = kv.next().unwrap_or_default().to_string();

            map.insert(k, v);
        }

        return Ok(Database {map: map});
    }

    fn insert(&mut self, key: String, value: String) {
        self.map.insert(key, value);
    }

    fn write(&self) -> R<()> {
        let mut contents = String::new();
        for (key, value) in &self.map {
            contents += &format!("{}={}\n", key, value);
        }
        return std::fs::write("kv.db", contents);
    }
}
<|endoftext|>


<commit_before>//! The peephole optimizir, which replaces common loop forms with single (non-Brainfuck)
//! instructions.
//!
//! For example, we detect the pattern `[-]`, which decrements the current byte until it reaches
//! zero, and replaces it with the [`SetZero`](../../src/bf/peephole/mod.rs.html#21-22)
//! instruction. See the [`Instruction`](enum.Instruction.html) enum for a list of the
//! instructions produced by the [peephole compiler](fn.compile.html).

mod interpreter;
mod compiler;

pub use self::compiler::compile;

/// At this level, a program is a rose tree of instructions.
///
/// All instructions are leaves except for the `Loop` instruction, which contains a boxed `Program`.
pub type Program = [Instruction];

/// Instructions as output by the peephole optimizer.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Instruction {
    /// Decrease the pointer by the specified offset.
    Left(usize),
    /// Increase the pointer by the specified offset.
    Right(usize),
    /// Increase the current byte value by the specified offset.
    ///
    /// Because arithmetic is modulo 256, this implements subtraction as well as addition.
    Change(u8),
    /// Read a byte of input.
    In,
    /// Write a byte of output.
    Out,
    /// Set the current byte value to 0.
    ///
    /// Equivalent to the concrete Braincode loop `[-]`.
    SetZero,
    /// Add the byte at the pointer to the byte at the specified offset and zero the byte at the
    /// pointer.
    ///
    /// `OffsetAddRight(5)` is equivalent to the concrete Brainfuck loop `[->>>>>+<<<<<]`.
    OffsetAddRight(usize),
    /// Add the byte at the pointer to the byte at the specified offset and zero the byte at the
    /// pointer.
    ///
    /// `OffsetAddRight(5)` is equivalent to the concrete Brainfuck loop `[-<<<<<+>>>>>]`.
    OffsetAddLeft(usize),
    /// Finds the nearest zero to the left that appears offset by a multiple of the given `usize`.
    ///
    /// `FindZeroRight(3)` is equivalent to the concrete Brainfuck loop `[>>>]`.
    FindZeroRight(usize),
    /// Finds the nearest zero to the right that appears offset by a multiple of the given `usize`.
    ///
    /// `FindZeroLeft(3)` is equivalent to the concrete Brainfuck loop `[<<<]`.
    FindZeroLeft(usize),
    /// A loop.
    Loop(Box<[Instruction]>),
}<commit_msg>s/optimizir/optimizer/<commit_after>//! The peephole optimizer, which replaces common loop forms with single (non-Brainfuck)
//! instructions.
//!
//! For example, we detect the pattern `[-]`, which decrements the current byte until it reaches
//! zero, and replaces it with the [`SetZero`](../../src/bf/peephole/mod.rs.html#21-22)
//! instruction. See the [`Instruction`](enum.Instruction.html) enum for a list of the
//! instructions produced by the [peephole compiler](fn.compile.html).

mod interpreter;
mod compiler;

pub use self::compiler::compile;

/// At this level, a program is a rose tree of instructions.
///
/// All instructions are leaves except for the `Loop` instruction, which contains a boxed `Program`.
pub type Program = [Instruction];

/// Instructions as output by the peephole optimizer.
#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Instruction {
    /// Decrease the pointer by the specified offset.
    Left(usize),
    /// Increase the pointer by the specified offset.
    Right(usize),
    /// Increase the current byte value by the specified offset.
    ///
    /// Because arithmetic is modulo 256, this implements subtraction as well as addition.
    Change(u8),
    /// Read a byte of input.
    In,
    /// Write a byte of output.
    Out,
    /// Set the current byte value to 0.
    ///
    /// Equivalent to the concrete Braincode loop `[-]`.
    SetZero,
    /// Add the byte at the pointer to the byte at the specified offset and zero the byte at the
    /// pointer.
    ///
    /// `OffsetAddRight(5)` is equivalent to the concrete Brainfuck loop `[->>>>>+<<<<<]`.
    OffsetAddRight(usize),
    /// Add the byte at the pointer to the byte at the specified offset and zero the byte at the
    /// pointer.
    ///
    /// `OffsetAddRight(5)` is equivalent to the concrete Brainfuck loop `[-<<<<<+>>>>>]`.
    OffsetAddLeft(usize),
    /// Finds the nearest zero to the left that appears offset by a multiple of the given `usize`.
    ///
    /// `FindZeroRight(3)` is equivalent to the concrete Brainfuck loop `[>>>]`.
    FindZeroRight(usize),
    /// Finds the nearest zero to the right that appears offset by a multiple of the given `usize`.
    ///
    /// `FindZeroLeft(3)` is equivalent to the concrete Brainfuck loop `[<<<]`.
    FindZeroLeft(usize),
    /// A loop.
    Loop(Box<[Instruction]>),
}<|endoftext|>


<commit_before>#![feature(convert)]
#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;

struct VM<'a> {
  stack: Vec<i64>,
  instructions: Vec<&'a str>
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions
    }
  }

  pub fn run(&mut self) {
    // just some aliases for brevity
    let ref mut stack = self.stack;
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", n] => stack.push(n.parse::<i64>().unwrap()),
        ["add"] => if let (Some(arg1), Some(arg2)) = (stack.pop(), stack.pop()) {
          stack.push(arg1 + arg2);
        } else {
          println!("VM error: not enough arguments to `add`");
        },

        ["say"] => if let Some(arg) = stack.pop() {
          println!("hey {}", arg);
        } else {
          println!("VM error: not enough arguments to `say`");
        },

        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we're not conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if (how == "carry") {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["invert_carry"] => carry = !carry,

        [""] => (), // just trap this for now
        [..] => println!("VM error: Unrecognized instruction!"), // todo err!
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          let mut vm = VM::new(content.split('\n').collect());
          vm.run();
        }
      },
      Err(err) => {
        println!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    println!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<commit_msg>Implement hash-based "local" variables + cmp<commit_after>#![feature(convert)]
#![feature(slice_patterns)]
use std::env;
use std::fs::File;
use std::io::Read;
use std::collections::HashMap;

type Expr = i64;

struct VM<'a> {
  stack: Vec<Expr>,
  instructions: Vec<&'a str>,
  locals: HashMap<&'a str, Expr>,
}

impl<'a> VM<'a> {
  pub fn new(instructions: Vec<&'a str>) -> VM {
    VM {
      stack: Vec::new(),
      instructions: instructions,
      locals: HashMap::new(),
    }
  }

  /*urgh rust. can't borrow self as mut more than once, heh...
  fn unsafe_pop(&mut self) -> Expr {
    match self.stack.pop() {
      Some(expr) => expr,
      None => panic!("VM error: can't pop stack!")
    }
  }*/

  pub fn run(&mut self) {
    // just some aliases for brevity
    let ref mut stack = self.stack;
    let ref mut locals = self.locals;
    let len = self.instructions.len();

    // VM variables (might be moved back to the struct itself)
    let mut ip = 0; // instruction pointer
    let mut carry = false;

    while ip < len {
      let instr = self.instructions[ip];
      ip += 1;
      match instr.split(" ").collect::<Vec<_>>().as_slice() {
        ["push", n] => stack.push(n.parse::<i64>().unwrap()),
        ["add"] => if let (Some(arg1), Some(arg2)) = (stack.pop(), stack.pop()) {
          stack.push(arg1 + arg2);
        } else {
          println!("VM error: not enough arguments to `add`");
        },

        ["say"] => if let Some(arg) = stack.pop() {
          println!("hey {}", arg);
        } else {
          println!("VM error: not enough arguments to `say`");
        },

        //["cmp", "<"] =>

        // how = "carry" | "always"
        ["jump", how, n] => {
          let new_ip = n.parse::<usize>().unwrap();

          if new_ip < len {
            // only check carry if we're not conditionally jumping
            if how != "carry" || carry {
              ip = new_ip;
            }
            // only reset carry if it was used
            if how == "carry" {
              carry = false;
            }
          } else {
            panic!("VM error: trying to jump past end of bytecode ({} > {})", new_ip, len);
          }
        },

        ["invert_carry"] => carry = !carry,

        // NOTE: it's stack[*-1] OP stack[*-2]
        // which means if have stack=[1, 2]
        // you'll have 2 OP 1
        ["cmp", op] => if let (Some(arg1), Some(arg2)) = (stack.pop(), stack.pop()) {
          carry = match op {
            "<" => arg1 < arg2,
            ">" => arg1 > arg2,
            "<=" => arg1 <= arg2,
            ">=" => arg1 >= arg2,
            "=" => arg1 == arg2,
            _ => panic!("VM error: unrecognized `cmp` operator: {}", op),
          };
        } else {
          panic!("VM error: not enough arguments to `cmp`");
        },

        ["local", "load", name] => match locals.get(name) {
          Some(expr) => stack.push(expr.clone()),
          None       => panic!("VM error: unknown local variable {}", name),
        },

        ["local", "store", name] => if let Some(arg) = stack.pop() {
          let _ = locals.insert(name, arg);
        } else {
          panic!("VM error: not enough arguments for `local store`");
        },

        [instr, ..] => panic!("VM error: no such instruction {}", instr),
        [..] => panic!("VM error: Unrecognized instruction!"), // todo err!
      }
    }
  }
}

fn main() {
	if let Some(path) = env::args().nth(1) {
		println!("Loading file {}", path);

    match File::open(&path) {
      Ok(mut file) => {
        let mut content = String::new();
        if let Ok(_) = file.read_to_string(&mut content) {
          // remove trailing newlines, split by line
          let instructions = content.trim_matches('\n').split('\n').collect();
          let mut vm = VM::new(instructions);
          vm.run();
        }
      },
      Err(err) => {
        println!("Can't read file {} (error: {})", path, err);
      }
    }
	} else {
    println!("Please give a file argument");
  }

  //     let path = Path::new("chry.fa");
  // let mut file = BufferedReader::new(File::open(&path));
  // for line in file.lines() {
  //  print!("{}", line.unwrap());
  //      }
}
<|endoftext|>


<commit_before>use super::helpers::fixtures::get_language;
use tree_sitter_tags::{TagKind, TagsConfiguration, TagsContext};

#[test]
fn test_tags_python() {
    let language = get_language("python");
    let tags_config = TagsConfiguration::new(
        language,
        r#"
        ((function_definition
          name: (identifier) @name
          body: (block . (expression_statement (string) @doc))) @function
         (strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)"))
        (function_definition
          name: (identifier) @name) @function
        ((class_definition
          name: (identifier) @name
          body: (block . (expression_statement (string) @doc))) @class
         (strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)"))
        (class_definition
          name: (identifier) @name) @class
        (call
          function: (identifier) @name) @call
        "#,
        "",
    )
    .unwrap();

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(
            &tags_config,
            br#"
        class Customer:
            """
            Data about a customer
            """

            def age(self):
                '''
                Get the customer's age
                '''
                compute_age(self.id)
        }
        "#,
        )
        .collect::<Vec<_>>();

    assert_eq!(
        tags.iter().map(|t| (t.name, t.kind)).collect::<Vec<_>>(),
        &[
            ("Customer", TagKind::Class),
            ("age", TagKind::Function),
            ("compute_age", TagKind::Call),
        ]
    );

    assert_eq!(tags[0].docs.as_ref().unwrap(), "Data about a customer");
    assert_eq!(tags[0].line, "class Customer:");
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
}

#[test]
fn test_tags_javascript() {
    let language = get_language("javascript");
    let tags_config = TagsConfiguration::new(
        language,
        r#"
        ((*
          (comment)+ @doc
          .
          (class_declaration
            name: (identifier) @name) @class)
         (select-adjacent! @doc @class)
         (strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)"))
        ((*
          (comment)+ @doc
          .
          (method_definition
            name: (property_identifier) @name) @method)
;         (select-adjacent! @doc @method)
         (strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)"))
        "#,
        "",
    )
    .unwrap();

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(
            &tags_config,
            br#"
            // hi

            // Data about a customer.
            // bla bla bla
            class Customer {
                /*
                 * Get the customer's age
                 */
                getAge() {
                }
            }
            "#,
        )
        .collect::<Vec<_>>();

    assert_eq!(
        tags.iter().map(|t| (t.name, t.kind)).collect::<Vec<_>>(),
        &[("getAge", TagKind::Method), ("Customer", TagKind::Class)]
    );
    assert_eq!(tags[0].docs.as_ref().unwrap(), "Get the customer's age");
    assert_eq!(
        tags[1].docs.as_ref().unwrap(),
        "Data about a customer.\nbla bla bla"
    );
}
<commit_msg>tags: Add test where no comments are adjacent to definition<commit_after>use super::helpers::fixtures::get_language;
use tree_sitter_tags::{TagKind, TagsConfiguration, TagsContext};

#[test]
fn test_tags_python() {
    let language = get_language("python");
    let tags_config = TagsConfiguration::new(
        language,
        r#"
        ((function_definition
          name: (identifier) @name
          body: (block . (expression_statement (string) @doc))) @function
         (strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)"))
        (function_definition
          name: (identifier) @name) @function
        ((class_definition
          name: (identifier) @name
          body: (block . (expression_statement (string) @doc))) @class
         (strip! @doc "(^['\"\\s]*)|(['\"\\s]*$)"))
        (class_definition
          name: (identifier) @name) @class
        (call
          function: (identifier) @name) @call
        "#,
        "",
    )
    .unwrap();

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(
            &tags_config,
            br#"
        class Customer:
            """
            Data about a customer
            """

            def age(self):
                '''
                Get the customer's age
                '''
                compute_age(self.id)
        }
        "#,
        )
        .collect::<Vec<_>>();

    assert_eq!(
        tags.iter().map(|t| (t.name, t.kind)).collect::<Vec<_>>(),
        &[
            ("Customer", TagKind::Class),
            ("age", TagKind::Function),
            ("compute_age", TagKind::Call),
        ]
    );

    assert_eq!(tags[0].docs.as_ref().unwrap(), "Data about a customer");
    assert_eq!(tags[0].line, "class Customer:");
    assert_eq!(tags[1].docs.as_ref().unwrap(), "Get the customer's age");
}

#[test]
fn test_tags_javascript() {
    let language = get_language("javascript");
    let tags_config = TagsConfiguration::new(
        language,
        r#"
        ((*
          (comment)+ @doc
          .
          (class_declaration
            name: (identifier) @name) @class)
         (select-adjacent! @doc @class)
         (strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)"))
        ((*
          (comment)+ @doc
          .
          (method_definition
            name: (property_identifier) @name) @method)
;         (select-adjacent! @doc @method)
         (strip! @doc "(^[/\\*\\s]*)|([/\\*\\s]*$)"))
        "#,
        "",
    )
    .unwrap();

    let mut tag_context = TagsContext::new();
    let tags = tag_context
        .generate_tags(
            &tags_config,
            br#"
            // hi

            // Data about a customer.
            // bla bla bla
            class Customer {
                /*
                 * Get the customer's age
                 */
                getAge() {
                }
            }

            // ok

            class Agent {

            }
            "#,
        )
        .collect::<Vec<_>>();

    assert_eq!(
        tags.iter().map(|t| (t.name, t.kind)).collect::<Vec<_>>(),
        &[
            ("getAge", TagKind::Method),
            ("Customer", TagKind::Class),
            ("Agent", TagKind::Class)
        ]
    );
    assert_eq!(tags[0].docs.as_ref().unwrap(), "Get the customer's age");
    assert_eq!(
        tags[1].docs.as_ref().unwrap(),
        "Data about a customer.\nbla bla bla"
    );
    assert_eq!(tags[2].docs, None);
}
<|endoftext|>


<commit_before>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use futures::{future, Future};
use hyper::{Error, Client, Method, Uri, Headers, Body, Request};
use hyper::client::{HttpConnector, Response};

use server::listen::LISTEN_REMOTE;
use APP_CONF;

const MAX_SHARDS: u8 = 16;

lazy_static! {
    static ref SHARD_REGISTER: [Option<Uri>; MAX_SHARDS as usize] = map_shards();
}

thread_local! {
    static TUNNEL_CLIENT: Client<HttpConnector> = make_client();
}

pub struct ProxyTunnel;

pub type ProxyTunnelFuture = Box<Future<Item = Response, Error = Error>>;

fn make_client() -> Client<HttpConnector> {
    Client::configure()
        .keep_alive(true)
        .build(
            &LISTEN_REMOTE
                .lock().unwrap()
                .get_mut().to_owned().unwrap()
                .handle().unwrap()
        )
}

fn map_shards() -> [Option<Uri>; MAX_SHARDS as usize] {
    // Notice: this array cannot be initialized using the short format, as hyper::Uri doesnt \
    //   implement the Copy trait, hence the ugly hardcoded initialization vector w/ Nones.
    let mut shards = [
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None
    ];

    for shard in &APP_CONF.proxy.shard {
        // Shard number overflows?
        if shard.shard >= MAX_SHARDS {
            panic!("shard number overflows maximum of {} shards", MAX_SHARDS);
        }

        // Store this shard
        shards[shard.shard as usize] = Some(
            format!(
                "http://{}:{}",
                APP_CONF.proxy.shard[0].inet.ip(),
                APP_CONF.proxy.shard[0].inet.port()
            ).parse()
                .expect("could not build shard uri"),
        );
    }

    shards
}

impl ProxyTunnel {
    pub fn run(
        method: &Method,
        uri: &Uri,
        headers: &Headers,
        body: Body,
        shard: u8,
    ) -> ProxyTunnelFuture {
        if shard < MAX_SHARDS {
            // Route to target shard
            match SHARD_REGISTER[shard as usize] {
                Some(ref shard_uri) => {
                    let mut tunnel_uri = format!("{}{}", shard_uri, uri.path());

                    if let Some(query) = uri.query() {
                        tunnel_uri.push_str("?");
                        tunnel_uri.push_str(query);
                    }

                    match tunnel_uri.parse() {
                        Ok(tunnel_uri) => {
                            let mut tunnel_req = Request::new(method.to_owned(), tunnel_uri);

                            // Forward headers
                            {
                                let tunnel_headers = tunnel_req.headers_mut();

                                tunnel_headers.clone_from(headers);
                            }

                            // Forward body?
                            match method {
                                &Method::Post | &Method::Patch | &Method::Put => {
                                    tunnel_req.set_body(body);
                                }
                                _ => {}
                            }

                            TUNNEL_CLIENT.with(|client| Box::new(client.request(tunnel_req)))
                        }
                        Err(err) => Box::new(future::err(Error::Uri(err))),
                    }
                }
                None => Box::new(future::err(Error::Header)),
            }
        } else {
            // Shard out of bounds
            Box::new(future::err(Error::Header))
        }
    }
}
<commit_msg>Enable tunnel client keep-alive<commit_after>// Bloom
//
// HTTP REST API caching middleware
// Copyright: 2017, Valerian Saliou <valerian@valeriansaliou.name>
// License: Mozilla Public License v2.0 (MPL v2.0)

use std::time::Duration;
use futures::{future, Future};
use hyper::{Error, Client, Method, Uri, Headers, Body, Request};
use hyper::client::{HttpConnector, Response};

use server::listen::LISTEN_REMOTE;
use APP_CONF;

const MAX_SHARDS: u8 = 16;
const CLIENT_KEEP_ALIVE_TIMEOUT_SECONDS: u64 = 30;

lazy_static! {
    static ref SHARD_REGISTER: [Option<Uri>; MAX_SHARDS as usize] = map_shards();
}

thread_local! {
    static TUNNEL_CLIENT: Client<HttpConnector> = make_client();
}

pub struct ProxyTunnel;

pub type ProxyTunnelFuture = Box<Future<Item = Response, Error = Error>>;

fn make_client() -> Client<HttpConnector> {
    Client::configure()
        .keep_alive(true)
        .keep_alive_timeout(Some(Duration::from_secs(CLIENT_KEEP_ALIVE_TIMEOUT_SECONDS)))
        .build(
            &LISTEN_REMOTE
                .lock().unwrap()
                .get_mut().to_owned().unwrap()
                .handle().unwrap()
        )
}

fn map_shards() -> [Option<Uri>; MAX_SHARDS as usize] {
    // Notice: this array cannot be initialized using the short format, as hyper::Uri doesnt \
    //   implement the Copy trait, hence the ugly hardcoded initialization vector w/ Nones.
    let mut shards = [
        None, None, None, None, None, None, None, None,
        None, None, None, None, None, None, None, None
    ];

    for shard in &APP_CONF.proxy.shard {
        // Shard number overflows?
        if shard.shard >= MAX_SHARDS {
            panic!("shard number overflows maximum of {} shards", MAX_SHARDS);
        }

        // Store this shard
        shards[shard.shard as usize] = Some(
            format!(
                "http://{}:{}",
                APP_CONF.proxy.shard[0].inet.ip(),
                APP_CONF.proxy.shard[0].inet.port()
            ).parse()
                .expect("could not build shard uri"),
        );
    }

    shards
}

impl ProxyTunnel {
    pub fn run(
        method: &Method,
        uri: &Uri,
        headers: &Headers,
        body: Body,
        shard: u8,
    ) -> ProxyTunnelFuture {
        if shard < MAX_SHARDS {
            // Route to target shard
            match SHARD_REGISTER[shard as usize] {
                Some(ref shard_uri) => {
                    let mut tunnel_uri = format!("{}{}", shard_uri, uri.path());

                    if let Some(query) = uri.query() {
                        tunnel_uri.push_str("?");
                        tunnel_uri.push_str(query);
                    }

                    match tunnel_uri.parse() {
                        Ok(tunnel_uri) => {
                            let mut tunnel_req = Request::new(method.to_owned(), tunnel_uri);

                            // Forward headers
                            {
                                let tunnel_headers = tunnel_req.headers_mut();

                                tunnel_headers.clone_from(headers);
                            }

                            // Forward body?
                            match method {
                                &Method::Post | &Method::Patch | &Method::Put => {
                                    tunnel_req.set_body(body);
                                }
                                _ => {}
                            }

                            TUNNEL_CLIENT.with(|client| Box::new(client.request(tunnel_req)))
                        }
                        Err(err) => Box::new(future::err(Error::Uri(err))),
                    }
                }
                None => Box::new(future::err(Error::Header)),
            }
        } else {
            // Shard out of bounds
            Box::new(future::err(Error::Header))
        }
    }
}
<|endoftext|>


<commit_before>// Sings '99 Bottles of Beer'
fn main()
{
    for bottle in (0..100).rev()
    {
        if bottle > 1
        {
            println!("{} bottles of beer on the wall, {} bottles of beer.", bottle, bottle);
            if bottle > 2
            {
                println!("Take one down and pass it around, {} bottles of beer on the wall.", bottle - 1);
            } else
            {
                println!("Take one down and pass it around, 1 bottle of beer on the wall.");
            }
        } else
        {
            println!("1 bottle of beer on the wall, 1 bottle of beer.");
            println!("Take one down and pass it around, no more bottles of beer on the wall.");
        }
        println!("");
    }
    println!("No more bottles of beer on the wall, no more bottles of beer.");
    println!("Go to the store and buy some more, 99 bottles of beer on the wall.\n");
}
<commit_msg>Fix off-by-one issue and formatting<commit_after>// Sings '99 Bottles of Beer'
fn main()
{
    for bottle in (1..100).rev()
    {
        if bottle > 1
        {
            println!("{} bottles of beer on the wall, {} bottles of beer.", bottle, bottle);
            if bottle > 2
            {
                println!("Take one down and pass it around, {} bottles of beer on the wall.", bottle - 1);
            }
            else
            {
                println!("Take one down and pass it around, 1 bottle of beer on the wall.");
            }
        }
        else
        {
            println!("1 bottle of beer on the wall, 1 bottle of beer.");
            println!("Take one down and pass it around, no more bottles of beer on the wall.");
        }
        println!("");
    }
    println!("No more bottles of beer on the wall, no more bottles of beer.");
    println!("Go to the store and buy some more, 99 bottles of beer on the wall.\n");
}
<|endoftext|>


<commit_before>#![feature(if_let)]
#![feature(phase)]

#[phase(plugin)]
extern crate json_macros;

extern crate serialize;

use serialize::{Encodable, json};
use serialize::json::PrettyEncoder;

#[deriving(Decodable, Encodable)]
struct Photo {
    url: String,
    dimensions: (uint, uint),
}

#[deriving(Decodable, Encodable)]
struct User {
    name: String,
    post_count: uint,
    likes_burgers: bool,
    avatar: Option<Photo>,
}

fn main() {
    println!("24 days of Rust - json (day 6)");
    println!("{}", json::encode(&42i));
    println!("{}", json::encode(&vec!["to", "be", "or", "not", "to", "be"]));
    println!("{}", json::encode(&Some(true)));
    let user = User {
        name: "Zbyszek".to_string(),
        post_count: 100u,
        likes_burgers: true,
        avatar: Some(Photo {
            url: "http://lorempixel.com/160/160/".to_string(),
            dimensions: (160u, 160u),
        }),
    };
    println!("{}", json::encode(&user));
    let mut buffer: Vec<u8> = Vec::new();
    {
        let mut encoder = PrettyEncoder::new(&mut buffer);
        user.encode(&mut encoder).ok().expect("JSON encode error");
    }
    let encoded = String::from_utf8(buffer).unwrap();
    println!("{}", encoded);
    let incoming_request = "{\"name\":\"John\",\"post_count\":2,\"likes_burgers\":false,\"avatar\":null}";
    let decoded: User = json::decode(incoming_request).unwrap();
    println!("My name is {} and I {} burgers",
        decoded.name, if decoded.likes_burgers { "love" } else { "don't like" });
    assert!(decoded.avatar.is_none());
    let new_request = "{\"id\":64,\"title\":\"24days\",\"stats\":{\"pageviews\":1500}}";
    if let Ok(request_json) = json::from_str(new_request) {
        if let Some(ref stats) = request_json.find("stats") {
            if let Some(ref pageviews) = stats.find("pageviews") {
                println!("Pageviews: {}", pageviews);
            }
        }
    }
    let config = json!({
        "hostname": "localhost",
        "port": 6543,
        "allowed_methods": ["get", "post"],
        "limits": {
            "bandwidth": (500 * 16u),
            "rate": null
        }
    });
    println!("Configuration: {}", config);
    println!("Bandwidth: {}", config.search("bandwidth").unwrap());
}
<commit_msg>if let no longer behind feature gate<commit_after>#![feature(phase)]

#[phase(plugin)]
extern crate json_macros;

extern crate serialize;

use serialize::{Encodable, json};
use serialize::json::PrettyEncoder;

#[deriving(Decodable, Encodable)]
struct Photo {
    url: String,
    dimensions: (uint, uint),
}

#[deriving(Decodable, Encodable)]
struct User {
    name: String,
    post_count: uint,
    likes_burgers: bool,
    avatar: Option<Photo>,
}

fn main() {
    println!("24 days of Rust - json (day 6)");
    println!("{}", json::encode(&42i));
    println!("{}", json::encode(&vec!["to", "be", "or", "not", "to", "be"]));
    println!("{}", json::encode(&Some(true)));
    let user = User {
        name: "Zbyszek".to_string(),
        post_count: 100u,
        likes_burgers: true,
        avatar: Some(Photo {
            url: "http://lorempixel.com/160/160/".to_string(),
            dimensions: (160u, 160u),
        }),
    };
    println!("{}", json::encode(&user));
    let mut buffer: Vec<u8> = Vec::new();
    {
        let mut encoder = PrettyEncoder::new(&mut buffer);
        user.encode(&mut encoder).ok().expect("JSON encode error");
    }
    let encoded = String::from_utf8(buffer).unwrap();
    println!("{}", encoded);
    let incoming_request = "{\"name\":\"John\",\"post_count\":2,\"likes_burgers\":false,\"avatar\":null}";
    let decoded: User = json::decode(incoming_request).unwrap();
    println!("My name is {} and I {} burgers",
        decoded.name, if decoded.likes_burgers { "love" } else { "don't like" });
    assert!(decoded.avatar.is_none());
    let new_request = "{\"id\":64,\"title\":\"24days\",\"stats\":{\"pageviews\":1500}}";
    if let Ok(request_json) = json::from_str(new_request) {
        if let Some(ref stats) = request_json.find("stats") {
            if let Some(ref pageviews) = stats.find("pageviews") {
                println!("Pageviews: {}", pageviews);
            }
        }
    }
    let config = json!({
        "hostname": "localhost",
        "port": 6543,
        "allowed_methods": ["get", "post"],
        "limits": {
            "bandwidth": (500 * 16u),
            "rate": null
        }
    });
    println!("Configuration: {}", config);
    println!("Bandwidth: {}", config.search("bandwidth").unwrap());
}
<|endoftext|>


<commit_before>use std::io::stdin;
use std::io::stdout;
use std::str;
use protobuf::plugin::*;
use protobuf::parse_from_reader;
use protobuf::Message;
use protobuf::descriptor::FileDescriptorProto;

pub struct GenRequest<'a> {
    pub file_descriptors: &'a [FileDescriptorProto],
    pub files_to_generate: &'a [String],
}

pub struct GenResult {
    pub name: String,
    pub content: Vec<u8>,
}

pub fn plugin_main<F>(gen: F)
    where F : Fn(&GenRequest) -> Vec<GenResult>
{
    let req = parse_from_reader::<CodeGeneratorRequest>(&mut stdin()).unwrap();
    let result = gen(&GenRequest {
        file_descriptors: &req.proto_file,
        files_to_generate: &req.file_to_generate,
    });
    let mut resp = CodeGeneratorResponse::new();
    resp.file =
        result
            .iter()
            .map(|file| {
                let mut r = CodeGeneratorResponse_File::new();
                r.set_name(file.name.to_string());
                r.set_content(str::from_utf8(file.content.as_ref()).unwrap().to_string());
                r
            })
            .collect();
    resp.write_to_writer(&mut stdout()).unwrap();
}
<commit_msg>Preserve parameter passed from protoc<commit_after>use std::io::stdin;
use std::io::stdout;
use std::str;
use protobuf::plugin::*;
use protobuf::parse_from_reader;
use protobuf::Message;
use protobuf::descriptor::FileDescriptorProto;

pub struct GenRequest<'a> {
    pub file_descriptors: &'a [FileDescriptorProto],
    pub files_to_generate: &'a [String],
    pub parameter: &'a str,
}

pub struct GenResult {
    pub name: String,
    pub content: Vec<u8>,
}

pub fn plugin_main<F>(gen: F)
    where F : Fn(&GenRequest) -> Vec<GenResult>
{
    let req = parse_from_reader::<CodeGeneratorRequest>(&mut stdin()).unwrap();
    let result = gen(&GenRequest {
        file_descriptors: &req.proto_file,
        files_to_generate: &req.file_to_generate,
        parameter: req.get_parameter(),
    });
    let mut resp = CodeGeneratorResponse::new();
    resp.file =
        result
            .iter()
            .map(|file| {
                let mut r = CodeGeneratorResponse_File::new();
                r.set_name(file.name.to_string());
                r.set_content(str::from_utf8(file.content.as_ref()).unwrap().to_string());
                r
            })
            .collect();
    resp.write_to_writer(&mut stdout()).unwrap();
}
<|endoftext|>