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

use std::fmt;

use text_writer::{mod, TextWriter};

use super::Token;

pub trait ToCss for Sized? {
    /// Serialize `self` in CSS syntax, writing to `dest`.
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter;

    /// Serialize `self` in CSS syntax and return a string.
    ///
    /// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
    #[inline]
    fn to_css_string(&self) -> String {
        let mut s = String::new();
        self.to_css(&mut s).unwrap();
        s
    }

    /// Serialize `self` in CSS syntax and return a result compatible with `std::fmt::Show`.
    ///
    /// Typical usage is, for a `Foo` that implements `ToCss`:
    ///
    /// ```{rust,ignore}
    /// use std::fmt;
    /// impl fmt::Show for Foo {
    ///     #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
    /// }
    /// ```
    ///
    /// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
    #[inline]
    fn fmt_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: TextWriter {
        self.to_css(dest).map_err(|_| fmt::WriteError)
    }
}

impl ToCss for Token {
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
        match *self {
            Token::Ident(ref value) => try!(serialize_identifier(value.as_slice(), dest)),
            Token::AtKeyword(ref value) => {
                try!(dest.write_char('@'));
                try!(serialize_identifier(value.as_slice(), dest));
            },
            Token::Hash(ref value) => {
                try!(dest.write_char('#'));
                for c in value.as_slice().chars() {
                    try!(serialize_char(c, dest, /* is_identifier_start = */ false));
                }
            },
            Token::IDHash(ref value) => {
                try!(dest.write_char('#'));
                try!(serialize_identifier(value.as_slice(), dest));
            }
            Token::QuotedString(ref value) => try!(serialize_string(value.as_slice(), dest)),
            Token::Url(ref value) => {
                try!(dest.write_str("url("));
                try!(serialize_string(value.as_slice(), dest));
                try!(dest.write_char(')'));
            },
            Token::Delim(value) => try!(dest.write_char(value)),

            Token::Number(ref value) => try!(dest.write_str(value.representation.as_slice())),
            Token::Percentage(ref value) => {
                try!(dest.write_str(value.representation.as_slice()));
                try!(dest.write_char('%'));
            },
            Token::Dimension(ref value, ref unit) => {
                try!(dest.write_str(value.representation.as_slice()));
                // Disambiguate with scientific notation.
                let unit = unit.as_slice();
                if unit == "e" || unit == "E" || unit.starts_with("e-") || unit.starts_with("E-") {
                    try!(dest.write_str("\\65 "));
                    for c in unit.slice_from(1).chars() {
                        try!(serialize_char(c, dest, /* is_identifier_start = */ false));
                    }
                } else {
                    try!(serialize_identifier(unit, dest));
                }
            },

            Token::UnicodeRange(start, end) => {
                try!(dest.write_str(format!("U+{:X}", start).as_slice()));
                if end != start {
                    try!(dest.write_str(format!("-{:X}", end).as_slice()));
                }
            }

            Token::WhiteSpace => try!(dest.write_char(' ')),
            Token::Colon => try!(dest.write_char(':')),
            Token::Semicolon => try!(dest.write_char(';')),
            Token::Comma => try!(dest.write_char(',')),
            Token::IncludeMatch => try!(dest.write_str("~=")),
            Token::DashMatch => try!(dest.write_str("|=")),
            Token::PrefixMatch => try!(dest.write_str("^=")),
            Token::SuffixMatch => try!(dest.write_str("$=")),
            Token::SubstringMatch => try!(dest.write_str("*=")),
            Token::Column => try!(dest.write_str("||")),
            Token::CDO => try!(dest.write_str("<!--")),
            Token::CDC => try!(dest.write_str("-->")),

            Token::Function(ref name) => {
                try!(serialize_identifier(name.as_slice(), dest));
                try!(dest.write_char('('));
            },
            Token::ParenthesisBlock => try!(dest.write_char('(')),
            Token::SquareBracketBlock => try!(dest.write_char('[')),
            Token::CurlyBracketBlock => try!(dest.write_char('{')),

            Token::BadUrl => try!(dest.write_str("url(<bad url>)")),
            Token::BadString => try!(dest.write_str("\"<bad string>\n")),
            Token::CloseParenthesis => try!(dest.write_char(')')),
            Token::CloseSquareBracket => try!(dest.write_char(']')),
            Token::CloseCurlyBracket => try!(dest.write_char('}')),
        }
        Ok(())
    }
}

pub fn serialize_identifier<W>(value: &str, dest: &mut W) -> text_writer::Result
where W:TextWriter {
    // TODO: avoid decoding/re-encoding UTF-8?
    let mut iter = value.chars();
    let mut c = iter.next().unwrap();
    if c == '-' {
        c = match iter.next() {
            None => return dest.write_str("\\-"),
            Some(c) => { try!(dest.write_char('-')); c },
        }
    };
    try!(serialize_char(c, dest, /* is_identifier_start = */ true));
    for c in iter {
        try!(serialize_char(c, dest, /* is_identifier_start = */ false));
    }
    Ok(())
}

#[inline]
fn serialize_char<W>(c: char, dest: &mut W, is_identifier_start: bool) -> text_writer::Result
where W: TextWriter {
    match c {
        '0'...'9' if is_identifier_start => try!(dest.write_str(format!("\\3{} ", c).as_slice())),
        '-' if is_identifier_start => try!(dest.write_str("\\-")),
        '0'...'9' | 'A'...'Z' | 'a'...'z' | '_' | '-' => try!(dest.write_char(c)),
        _ if c > '\x7F' => try!(dest.write_char(c)),
        '\n' => try!(dest.write_str("\\A ")),
        '\r' => try!(dest.write_str("\\D ")),
        '\x0C' => try!(dest.write_str("\\C ")),
        _ => { try!(dest.write_char('\\')); try!(dest.write_char(c)) },
    };
    Ok(())
}

pub fn serialize_string<W>(value: &str, dest: &mut W) -> text_writer::Result
where W: TextWriter {
    try!(dest.write_char('"'));
    try!(CssStringWriter::new(dest).write_str(value));
    try!(dest.write_char('"'));
    Ok(())
}

/// A `TextWriter` adaptor that escapes text for writing as a CSS string.
/// Quotes are not included.
///
/// Typical usage:
///
/// ```{rust,ignore}
/// fn write_foo<W>(foo: &Foo, dest: &mut W) -> text_writer::Result where W: TextWriter {
///     try!(dest.write_char('"'));
///     {
///         let mut string_dest = CssStringWriter::new(dest);
///         // Write into string_dest...
///     }
///     try!(dest.write_char('"'));
///     Ok(())
/// }
/// ```
pub struct CssStringWriter<'a, W: 'a> {
    inner: &'a mut W,
}

impl<'a, W> CssStringWriter<'a, W> where W: TextWriter {
    pub fn new(inner: &'a mut W) -> CssStringWriter<'a, W> {
        CssStringWriter { inner: inner }
    }
}

impl<'a, W> TextWriter for CssStringWriter<'a, W> where W: TextWriter {
    fn write_str(&mut self, s: &str) -> text_writer::Result {
        // TODO: avoid decoding/re-encoding UTF-8?
        for c in s.chars() {
            try!(self.write_char(c))
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> text_writer::Result {
        match c {
            '"' => self.inner.write_str("\\\""),
            '\\' => self.inner.write_str("\\\\"),
            '\n' => self.inner.write_str("\\A "),
            '\r' => self.inner.write_str("\\D "),
            '\x0C' => self.inner.write_str("\\C "),
            _ => self.inner.write_char(c),
        }
    }
}

impl<'a> ToCss for [Token] {
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
        use Token::*;

        let mut iter = self.iter();
        let mut previous = match iter.next() {
            None => return Ok(()),
            Some(first) => { try!(first.to_css(dest)); first }
        };
        // This does not borrow-check: for component_value in iter {
        loop { match iter.next() { None => break, Some(component_value) => {
            let (a, b) = (previous, component_value);
            if (
                matches!(*a, Ident(..) | AtKeyword(..) | Hash(..) | IDHash(..) |
                             Dimension(..) | Delim('#') | Delim('-') | Number(..)) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..) |
                             Number(..) | Percentage(..) | Dimension(..) | UnicodeRange(..))
            ) || (
                matches!(*a, Ident(..)) &&
                matches!(*b, ParenthesisBlock(..))
            ) || (
                matches!(*a, Ident(..) | AtKeyword(..) | Hash(..) | IDHash(..) | Dimension(..)) &&
                matches!(*b, Delim('-') | CDC)
            ) || (
                matches!(*a, Delim('#') | Delim('-') | Number(..) | Delim('@')) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..))
            ) || (
                matches!(*a, Delim('@')) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..) |
                             UnicodeRange(..) | Delim('-'))
            ) || (
                matches!(*a, UnicodeRange(..) | Delim('.') | Delim('+')) &&
                matches!(*b, Number(..) | Percentage(..) | Dimension(..))
            ) || (
                matches!(*a, UnicodeRange(..)) &&
                matches!(*b, Ident(..) | Function(..) | Delim('?'))
            ) || matches!((a, b), (&Delim(a), &Delim(b)) if matches!((a, b),
                ('#', '-') |
                ('$', '=') |
                ('*', '=') |
                ('^', '=') |
                ('~', '=') |
                ('|', '=') |
                ('|', '|') |
                ('/', '*')
            )) {
                try!(dest.write_str("/**/"));
            }
            // Skip whitespace when '\n' was previously written at the previous iteration.
            if !matches!((previous, component_value), (&Delim('\\'), &WhiteSpace)) {
                try!(component_value.to_css(dest));
            }
            if component_value == &Delim('\\') {
                try!(dest.write_char('\n'));
            }
            previous = component_value;
        }}}
        Ok(())
    }
}
<commit_msg>Use `while let` instead of `loop` + `match` + `break`.<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

use std::fmt;

use text_writer::{mod, TextWriter};

use super::Token;

pub trait ToCss for Sized? {
    /// Serialize `self` in CSS syntax, writing to `dest`.
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter;

    /// Serialize `self` in CSS syntax and return a string.
    ///
    /// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
    #[inline]
    fn to_css_string(&self) -> String {
        let mut s = String::new();
        self.to_css(&mut s).unwrap();
        s
    }

    /// Serialize `self` in CSS syntax and return a result compatible with `std::fmt::Show`.
    ///
    /// Typical usage is, for a `Foo` that implements `ToCss`:
    ///
    /// ```{rust,ignore}
    /// use std::fmt;
    /// impl fmt::Show for Foo {
    ///     #[inline] fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.fmt_to_css(f) }
    /// }
    /// ```
    ///
    /// (This is a convenience wrapper for `to_css` and probably should not be overridden.)
    #[inline]
    fn fmt_to_css<W>(&self, dest: &mut W) -> fmt::Result where W: TextWriter {
        self.to_css(dest).map_err(|_| fmt::WriteError)
    }
}

impl ToCss for Token {
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
        match *self {
            Token::Ident(ref value) => try!(serialize_identifier(value.as_slice(), dest)),
            Token::AtKeyword(ref value) => {
                try!(dest.write_char('@'));
                try!(serialize_identifier(value.as_slice(), dest));
            },
            Token::Hash(ref value) => {
                try!(dest.write_char('#'));
                for c in value.as_slice().chars() {
                    try!(serialize_char(c, dest, /* is_identifier_start = */ false));
                }
            },
            Token::IDHash(ref value) => {
                try!(dest.write_char('#'));
                try!(serialize_identifier(value.as_slice(), dest));
            }
            Token::QuotedString(ref value) => try!(serialize_string(value.as_slice(), dest)),
            Token::Url(ref value) => {
                try!(dest.write_str("url("));
                try!(serialize_string(value.as_slice(), dest));
                try!(dest.write_char(')'));
            },
            Token::Delim(value) => try!(dest.write_char(value)),

            Token::Number(ref value) => try!(dest.write_str(value.representation.as_slice())),
            Token::Percentage(ref value) => {
                try!(dest.write_str(value.representation.as_slice()));
                try!(dest.write_char('%'));
            },
            Token::Dimension(ref value, ref unit) => {
                try!(dest.write_str(value.representation.as_slice()));
                // Disambiguate with scientific notation.
                let unit = unit.as_slice();
                if unit == "e" || unit == "E" || unit.starts_with("e-") || unit.starts_with("E-") {
                    try!(dest.write_str("\\65 "));
                    for c in unit.slice_from(1).chars() {
                        try!(serialize_char(c, dest, /* is_identifier_start = */ false));
                    }
                } else {
                    try!(serialize_identifier(unit, dest));
                }
            },

            Token::UnicodeRange(start, end) => {
                try!(dest.write_str(format!("U+{:X}", start).as_slice()));
                if end != start {
                    try!(dest.write_str(format!("-{:X}", end).as_slice()));
                }
            }

            Token::WhiteSpace => try!(dest.write_char(' ')),
            Token::Colon => try!(dest.write_char(':')),
            Token::Semicolon => try!(dest.write_char(';')),
            Token::Comma => try!(dest.write_char(',')),
            Token::IncludeMatch => try!(dest.write_str("~=")),
            Token::DashMatch => try!(dest.write_str("|=")),
            Token::PrefixMatch => try!(dest.write_str("^=")),
            Token::SuffixMatch => try!(dest.write_str("$=")),
            Token::SubstringMatch => try!(dest.write_str("*=")),
            Token::Column => try!(dest.write_str("||")),
            Token::CDO => try!(dest.write_str("<!--")),
            Token::CDC => try!(dest.write_str("-->")),

            Token::Function(ref name) => {
                try!(serialize_identifier(name.as_slice(), dest));
                try!(dest.write_char('('));
            },
            Token::ParenthesisBlock => try!(dest.write_char('(')),
            Token::SquareBracketBlock => try!(dest.write_char('[')),
            Token::CurlyBracketBlock => try!(dest.write_char('{')),

            Token::BadUrl => try!(dest.write_str("url(<bad url>)")),
            Token::BadString => try!(dest.write_str("\"<bad string>\n")),
            Token::CloseParenthesis => try!(dest.write_char(')')),
            Token::CloseSquareBracket => try!(dest.write_char(']')),
            Token::CloseCurlyBracket => try!(dest.write_char('}')),
        }
        Ok(())
    }
}

pub fn serialize_identifier<W>(value: &str, dest: &mut W) -> text_writer::Result
where W:TextWriter {
    // TODO: avoid decoding/re-encoding UTF-8?
    let mut iter = value.chars();
    let mut c = iter.next().unwrap();
    if c == '-' {
        c = match iter.next() {
            None => return dest.write_str("\\-"),
            Some(c) => { try!(dest.write_char('-')); c },
        }
    };
    try!(serialize_char(c, dest, /* is_identifier_start = */ true));
    for c in iter {
        try!(serialize_char(c, dest, /* is_identifier_start = */ false));
    }
    Ok(())
}

#[inline]
fn serialize_char<W>(c: char, dest: &mut W, is_identifier_start: bool) -> text_writer::Result
where W: TextWriter {
    match c {
        '0'...'9' if is_identifier_start => try!(dest.write_str(format!("\\3{} ", c).as_slice())),
        '-' if is_identifier_start => try!(dest.write_str("\\-")),
        '0'...'9' | 'A'...'Z' | 'a'...'z' | '_' | '-' => try!(dest.write_char(c)),
        _ if c > '\x7F' => try!(dest.write_char(c)),
        '\n' => try!(dest.write_str("\\A ")),
        '\r' => try!(dest.write_str("\\D ")),
        '\x0C' => try!(dest.write_str("\\C ")),
        _ => { try!(dest.write_char('\\')); try!(dest.write_char(c)) },
    };
    Ok(())
}

pub fn serialize_string<W>(value: &str, dest: &mut W) -> text_writer::Result
where W: TextWriter {
    try!(dest.write_char('"'));
    try!(CssStringWriter::new(dest).write_str(value));
    try!(dest.write_char('"'));
    Ok(())
}

/// A `TextWriter` adaptor that escapes text for writing as a CSS string.
/// Quotes are not included.
///
/// Typical usage:
///
/// ```{rust,ignore}
/// fn write_foo<W>(foo: &Foo, dest: &mut W) -> text_writer::Result where W: TextWriter {
///     try!(dest.write_char('"'));
///     {
///         let mut string_dest = CssStringWriter::new(dest);
///         // Write into string_dest...
///     }
///     try!(dest.write_char('"'));
///     Ok(())
/// }
/// ```
pub struct CssStringWriter<'a, W: 'a> {
    inner: &'a mut W,
}

impl<'a, W> CssStringWriter<'a, W> where W: TextWriter {
    pub fn new(inner: &'a mut W) -> CssStringWriter<'a, W> {
        CssStringWriter { inner: inner }
    }
}

impl<'a, W> TextWriter for CssStringWriter<'a, W> where W: TextWriter {
    fn write_str(&mut self, s: &str) -> text_writer::Result {
        // TODO: avoid decoding/re-encoding UTF-8?
        for c in s.chars() {
            try!(self.write_char(c))
        }
        Ok(())
    }

    fn write_char(&mut self, c: char) -> text_writer::Result {
        match c {
            '"' => self.inner.write_str("\\\""),
            '\\' => self.inner.write_str("\\\\"),
            '\n' => self.inner.write_str("\\A "),
            '\r' => self.inner.write_str("\\D "),
            '\x0C' => self.inner.write_str("\\C "),
            _ => self.inner.write_char(c),
        }
    }
}

impl<'a> ToCss for [Token] {
    fn to_css<W>(&self, dest: &mut W) -> text_writer::Result where W: TextWriter {
        use Token::*;

        let mut iter = self.iter();
        let mut previous = match iter.next() {
            None => return Ok(()),
            Some(first) => { try!(first.to_css(dest)); first }
        };
        while let Some(component_value) = iter.next() {
            let (a, b) = (previous, component_value);
            if (
                matches!(*a, Ident(..) | AtKeyword(..) | Hash(..) | IDHash(..) |
                             Dimension(..) | Delim('#') | Delim('-') | Number(..)) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..) |
                             Number(..) | Percentage(..) | Dimension(..) | UnicodeRange(..))
            ) || (
                matches!(*a, Ident(..)) &&
                matches!(*b, ParenthesisBlock(..))
            ) || (
                matches!(*a, Ident(..) | AtKeyword(..) | Hash(..) | IDHash(..) | Dimension(..)) &&
                matches!(*b, Delim('-') | CDC)
            ) || (
                matches!(*a, Delim('#') | Delim('-') | Number(..) | Delim('@')) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..))
            ) || (
                matches!(*a, Delim('@')) &&
                matches!(*b, Ident(..) | Function(..) | Url(..) | BadUrl(..) |
                             UnicodeRange(..) | Delim('-'))
            ) || (
                matches!(*a, UnicodeRange(..) | Delim('.') | Delim('+')) &&
                matches!(*b, Number(..) | Percentage(..) | Dimension(..))
            ) || (
                matches!(*a, UnicodeRange(..)) &&
                matches!(*b, Ident(..) | Function(..) | Delim('?'))
            ) || matches!((a, b), (&Delim(a), &Delim(b)) if matches!((a, b),
                ('#', '-') |
                ('$', '=') |
                ('*', '=') |
                ('^', '=') |
                ('~', '=') |
                ('|', '=') |
                ('|', '|') |
                ('/', '*')
            )) {
                try!(dest.write_str("/**/"));
            }
            // Skip whitespace when '\n' was previously written at the previous iteration.
            if !matches!((previous, component_value), (&Delim('\\'), &WhiteSpace)) {
                try!(component_value.to_css(dest));
            }
            if component_value == &Delim('\\') {
                try!(dest.write_char('\n'));
            }
            previous = component_value;
        }
        Ok(())
    }
}
<|endoftext|>


<commit_before>bitflags! {
    struct EntryModeFlags: u8 {
        const ENTRY_MODE            = 0b00000100;
        const CURSOR_MOVE_INCREMENT = 0b00000010;
        const DISPLAY_SHIFT_ENABLE  = 0b00000001;
        const CURSOR_MOVE_DECREMENT = 0b00000000;
        const DISPLAY_SHIFT_DISABLE = 0b00000000;
    }
}

/// Enumeration of possible methods to move.
pub enum MoveDirection {
    /// Moves right.
    Increment,
    /// Moves left.
    Decrement,
}

/// A struct for creating display entry mode settings.
pub struct EntryModeBuilder {
    move_direction: MoveDirection,
    display_shift: bool,
}

impl EntryModeBuilder {
    /// Make a new `EntryModeBuilder` with the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **move direction:**
    ///     - `Increment`
    ///  - **display_shift:**
    ///     - `Off`
    pub fn new() -> EntryModeBuilder {
        EntryModeBuilder {
            move_direction: MoveDirection::Increment,
            display_shift: false,
        }
    }

    /// Sets the direction the read/write cursor is moved when a character code is written to or
    /// read from the display.
    pub fn set_move_direction(&mut self, direction: MoveDirection) -> &mut EntryModeBuilder {
        self.move_direction = direction;
        self
    }

    /// Sets the display shift, which will be on character write, either `On` or `Off`.
    ///
    /// If display shift is enabled, it will seem as if the cursor does not move but the display
    /// does.
    ///
    /// **Note:** The display does not shift when reading.
    pub fn set_display_shift(&mut self, shift: bool) -> &mut EntryModeBuilder {
        self.display_shift = shift;
        self
    }

    pub fn build_command(&self) -> u8 {
        let mut cmd = ENTRY_MODE.bits();

        cmd |= match self.move_direction {
            MoveDirection::Increment => CURSOR_MOVE_INCREMENT.bits(),
            MoveDirection::Decrement => CURSOR_MOVE_DECREMENT.bits(),
        };

        cmd |= if self.display_shift {
            DISPLAY_SHIFT_ENABLE.bits()
        } else {
            DISPLAY_SHIFT_DISABLE.bits()
        };

        cmd
    }
}

impl Default for EntryModeBuilder {
    fn default() -> Self {
        Self::new()
    }
}
<commit_msg>Refactor entry mode builder<commit_after>bitflags! {
    struct EntryModeFlags: u8 {
        const ENTRY_MODE            = 0b00000100;
        const CURSOR_MOVE_INCREMENT = 0b00000010;
        const DISPLAY_SHIFT_ON      = 0b00000001;
        const CURSOR_MOVE_DECREMENT = 0b00000000;
        const DISPLAY_SHIFT_OFF     = 0b00000000;
    }
}

/// Enumeration of possible methods to move.
#[derive(Clone, Copy)]
pub enum MoveDirection {
    /// Moves right.
    Increment,
    /// Moves left.
    Decrement,
}

impl From<MoveDirection> for EntryModeFlags {
    fn from(direction: MoveDirection) -> Self {
        match direction {
            MoveDirection::Increment => CURSOR_MOVE_INCREMENT,
            MoveDirection::Decrement => CURSOR_MOVE_DECREMENT,
        }
    }
}

/// Enumeration to set display shift.
#[derive(Clone, Copy)]
pub enum DisplayShift {
    On,
    Off
}

impl From<DisplayShift> for EntryModeFlags {
    fn from(shift: DisplayShift) -> Self {
        match shift {
            DisplayShift::On => DISPLAY_SHIFT_ON,
            DisplayShift::Off => DISPLAY_SHIFT_OFF,
        }
    }
}

/// A struct for creating display entry mode settings.
pub struct EntryModeBuilder {
    move_direction: MoveDirection,
    display_shift: DisplayShift,
}

impl EntryModeBuilder {
    /// Make a new `EntryModeBuilder` with the default settings described below.
    ///
    /// The default settings are:
    ///
    ///  - **move direction:**
    ///     - `Increment`
    ///  - **display_shift:**
    ///     - `Off`
    pub fn new() -> EntryModeBuilder {
        EntryModeBuilder {
            move_direction: MoveDirection::Increment,
            display_shift: DisplayShift::Off,
        }
    }

    /// Sets the direction the read/write cursor is moved when a character code is written to or
    /// read from the display.
    pub fn set_move_direction(&mut self, direction: MoveDirection) -> &mut EntryModeBuilder {
        self.move_direction = direction;
        self
    }

    /// Sets the display shift, which will be performed on character write, either `On` or `Off`.
    ///
    /// If display shift is enabled, it will seem as if the cursor does not move but the display
    /// does.
    ///
    /// **Note:** The display does not shift when reading.
    pub fn set_display_shift(&mut self, shift: DisplayShift) -> &mut EntryModeBuilder {
        self.display_shift = shift;
        self
    }

    pub fn build_command(&self) -> u8 {
        let mut cmd = ENTRY_MODE;

        cmd |= EntryModeFlags::from(self.move_direction);
        cmd |= EntryModeFlags::from(self.display_shift);

        cmd.bits()
    }
}

impl Default for EntryModeBuilder {
    fn default() -> Self {
        Self::new()
    }
}
<|endoftext|>


<commit_before>/// Content type of the event `data` or `metadata`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl Into<i32> for ContentType {
    fn into(self) -> i32 {
        match self {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}
<commit_msg>content-type: Replace the Into impl by a From impl<commit_after>/// Content type of the event `data` or `metadata`.
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ContentType {
    /// Raw bytes
    Bytes,
    /// JSON values usable with projections in EventStore
    Json
}

impl From<ContentType> for i32 {
    fn from(content_type: ContentType) -> Self {
        match content_type {
            ContentType::Bytes => 0,
            ContentType::Json => 1,
        }
    }
}
<|endoftext|>


<commit_before>//! Conversion methods for JSON values.

use rustwlc::{Geometry, Point, Size};
use std::collections::BTreeMap;

use rlua;
use rustc_serialize::json::{Json, ToJson};

/// Converts a Json map into a Lua value
pub fn json_to_lua<'lua>(lua: &'lua rlua::Lua, json: Json)
                         -> Result<rlua::Value<'lua>, rlua::Error> {
    use rlua::Value;
    match json {
        Json::String(val)  => Ok(Value::String(lua.create_string(&val))),
        Json::Boolean(val) => Ok(Value::Boolean(val)),
        Json::F64(val)     => Ok(Value::Number(val)),
        Json::I64(val)     => Ok(Value::Number((val as i32) as f64)),
        Json::U64(val)     => Ok(Value::Number((val as u32) as f64)),
        Json::Null         => Ok(Value::Nil),
        Json::Array(vals)  => {
            let mut new_vals = Vec::with_capacity(vals.len());
            for (idx, val) in vals.into_iter().enumerate() {
                new_vals.push((idx, json_to_lua(lua, val)?));
            }
            lua.create_table_from(new_vals)
                .map(|table| Value::Table(table))
        },
        Json::Object(vals) => {
            let mut new_vals = BTreeMap::new();
            for (k, v) in vals {
                new_vals.insert(k, json_to_lua(lua, v)?);
            }
            lua.create_table_from(new_vals)
                .map(|table| Value::Table(table))
        }
    }
}

/// Converts an `rlua::Value` to a `Json`.
pub fn lua_to_json<'lua>(lua_value: rlua::Value<'lua>)
                         -> Result<Json, rlua::Error> {
    use rlua::Value::*;
    use rlua::Error;
    match lua_value {
        Nil => Ok(Json::Null),
        String(val) => Ok(Json::String(val.to_str().unwrap().into())),
        Number(val) => Ok(Json::F64(val)),
        Integer(val) => Ok(Json::I64(val as _)),
        Boolean(val) => Ok(Json::Boolean(val)),
        Table(arr) => lua_table_to_json(arr),
        _ => Err(Error::RuntimeError(
            format!("Did not expect {:#?}", lua_value)))
    }
}

/// Convert an AnyLuaValue to a Json array using numerical indicies.
///
/// # Result
/// This function returns an Err if the Lua object has a non-String key.
fn lua_table_to_json<'lua>(table: rlua::Table<'lua>)
                               -> Result<Json, rlua::Error> {
    use rlua::Value;
    use rlua::Error;
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for entry in table.clone().pairs::<Value, Value>() {
        let (key, _ )= entry?;
        match key {
            Value::Number(num) => {
                counter += num;
            }
            Value::String(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => return Err(Error::FromLuaConversionError {
                from: "Lua table",
                to: "JSON object",
                message: Some(format!("Could not convert {:#?}", table))
            })
        }
    }

    // Gauss' trick
    let len = table.len().unwrap();
    let desired_sum = (len * (len + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(table)
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(len as _);

    for entry in table.pairs::<Value, Value>() {
        let (_, val) = entry.unwrap();
        let lua_val = lua_to_json(val)?;
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

/// Converts an AnyLuaValue object to a Json object.
///
/// Will return an Err if the Lua object uses non-String keys.
fn lua_object_to_json<'lua>(table: rlua::Table<'lua>)
                          -> Result<Json, rlua::Error> {
    use rlua::{Value, Error};
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for entry in table.clone().pairs::<Value, Value>() {
        let (key, val) = entry.unwrap();
        match key {
            Value::String(text) => {
                let text = text.to_str().unwrap().into();
                json_obj.insert(text, lua_to_json(val.clone())?);
            },
            Value::Number(ix) => {
                json_obj.insert(ix.to_string(), lua_to_json(val.clone())?);
            }
            _ => {
                return Err(Error::RuntimeError(
                    format!("Did not expect {:#?}", table)))
            }
        }
    }
    Ok(Json::Object(json_obj))
}

pub fn size_to_json(size: Size) -> Json {
    let mut map = BTreeMap::new();
    map.insert("w".into(), size.w.to_json());
    map.insert("h".into(), size.h.to_json());
    map.to_json()
}

pub fn point_to_json(point: Point) -> Json {
    let mut map = BTreeMap::new();
    map.insert("x".into(), point.x.to_json());
    map.insert("y".into(), point.y.to_json());
    map.to_json()
}

pub fn geometry_to_json(geometry: Geometry) -> Json {
    let mut map = BTreeMap::new();
    let origin = point_to_json(geometry.origin);
    let size = size_to_json(geometry.size);
    map.insert("origin".into(), origin);
    map.insert("size".into(), size);
    map.to_json()
}
<commit_msg>Fixed conversion error in json_to_lua<commit_after>//! Conversion methods for JSON values.

use rustwlc::{Geometry, Point, Size};
use std::collections::BTreeMap;

use rlua;
use rustc_serialize::json::{Json, ToJson};

/// Converts a Json map into a Lua value
pub fn json_to_lua<'lua>(lua: &'lua rlua::Lua, json: Json)
                         -> Result<rlua::Value<'lua>, rlua::Error> {
    use rlua::Value;
    match json {
        Json::String(val)  => Ok(Value::String(lua.create_string(&val))),
        Json::Boolean(val) => Ok(Value::Boolean(val)),
        Json::F64(val)     => Ok(Value::Number(val)),
        Json::I64(val)     => Ok(Value::Number(val as f64)),
        Json::U64(val)     => Ok(Value::Number(val as f64)),
        Json::Null         => Ok(Value::Nil),
        Json::Array(vals)  => {
            let mut new_vals = Vec::with_capacity(vals.len());
            for (idx, val) in vals.into_iter().enumerate() {
                new_vals.push((idx, json_to_lua(lua, val)?));
            }
            lua.create_table_from(new_vals)
                .map(|table| Value::Table(table))
        },
        Json::Object(vals) => {
            let mut new_vals = BTreeMap::new();
            for (k, v) in vals {
                new_vals.insert(k, json_to_lua(lua, v)?);
            }
            lua.create_table_from(new_vals)
                .map(|table| Value::Table(table))
        }
    }
}

/// Converts an `rlua::Value` to a `Json`.
pub fn lua_to_json<'lua>(lua_value: rlua::Value<'lua>)
                         -> Result<Json, rlua::Error> {
    use rlua::Value::*;
    use rlua::Error;
    match lua_value {
        Nil => Ok(Json::Null),
        String(val) => Ok(Json::String(val.to_str().unwrap().into())),
        Number(val) => Ok(Json::F64(val)),
        Integer(val) => Ok(Json::I64(val as _)),
        Boolean(val) => Ok(Json::Boolean(val)),
        Table(arr) => lua_table_to_json(arr),
        _ => Err(Error::RuntimeError(
            format!("Did not expect {:#?}", lua_value)))
    }
}

/// Convert an AnyLuaValue to a Json array using numerical indicies.
///
/// # Result
/// This function returns an Err if the Lua object has a non-String key.
fn lua_table_to_json<'lua>(table: rlua::Table<'lua>)
                               -> Result<Json, rlua::Error> {
    use rlua::Value;
    use rlua::Error;
    // Check if every key is a number
    let mut counter = 0.0; // Account for first index?

    for entry in table.clone().pairs::<Value, Value>() {
        let (key, _ )= entry?;
        match key {
            Value::Number(num) => {
                counter += num;
            }
            Value::String(_) => {
                break;
            }
            // Non-string keys are not allowed
            _ => return Err(Error::FromLuaConversionError {
                from: "Lua table",
                to: "JSON object",
                message: Some(format!("Could not convert {:#?}", table))
            })
        }
    }

    // Gauss' trick
    let len = table.len().unwrap();
    let desired_sum = (len * (len + 1)) / 2;
    if counter != desired_sum as f64 {
        return lua_object_to_json(table)
    }

    let mut json_arr: Vec<Json> = Vec::with_capacity(len as _);

    for entry in table.pairs::<Value, Value>() {
        let (_, val) = entry.unwrap();
        let lua_val = lua_to_json(val)?;
        json_arr.push(lua_val);
    }
    Ok(Json::Array(json_arr))
}

/// Converts an AnyLuaValue object to a Json object.
///
/// Will return an Err if the Lua object uses non-String keys.
fn lua_object_to_json<'lua>(table: rlua::Table<'lua>)
                          -> Result<Json, rlua::Error> {
    use rlua::{Value, Error};
    let mut json_obj: BTreeMap<String, Json> = BTreeMap::new();

    for entry in table.clone().pairs::<Value, Value>() {
        let (key, val) = entry.unwrap();
        match key {
            Value::String(text) => {
                let text = text.to_str().unwrap().into();
                json_obj.insert(text, lua_to_json(val.clone())?);
            },
            Value::Number(ix) => {
                json_obj.insert(ix.to_string(), lua_to_json(val.clone())?);
            }
            _ => {
                return Err(Error::RuntimeError(
                    format!("Did not expect {:#?}", table)))
            }
        }
    }
    Ok(Json::Object(json_obj))
}

pub fn size_to_json(size: Size) -> Json {
    let mut map = BTreeMap::new();
    map.insert("w".into(), size.w.to_json());
    map.insert("h".into(), size.h.to_json());
    map.to_json()
}

pub fn point_to_json(point: Point) -> Json {
    let mut map = BTreeMap::new();
    map.insert("x".into(), point.x.to_json());
    map.insert("y".into(), point.y.to_json());
    map.to_json()
}

pub fn geometry_to_json(geometry: Geometry) -> Json {
    let mut map = BTreeMap::new();
    let origin = point_to_json(geometry.origin);
    let size = size_to_json(geometry.size);
    map.insert("origin".into(), origin);
    map.insert("size".into(), size);
    map.to_json()
}
<|endoftext|>


<commit_before>use std::sync::mpsc;

use platform::time::sleep_secs;
use platform::time::time_now;
use testlib::cmp::eq_f64;

use super::LiveTimers;
use super::MetricsRecorder;
use super::TimeSeries;
use super::Timer;
use super::Timing;

#[test]
#[should_panic]
fn test_live_timers_name_mismatch() {
    let mut lt = LiveTimers::new();

    lt.start("cmd");
    lt.stop("resp"); // panic expected
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_live_timers_ok() {
    let mut lt = LiveTimers::new();

    let t1 = time_now();
    let start_time = lt.start("cmd");
    // start_time is very close to *now*
    assert!(eq_f64(t1, start_time, 0.01));
    // "cmd" -> start_time was added to the map
    assert_eq!(&start_time, lt.get_timers().get("cmd").unwrap());

    sleep_secs(0.25);

    let timing = lt.stop("cmd");
    // the returned start_time matches what we saw before
    assert_eq!(start_time, timing.start_time);
    // the duration is almost exactly the time we slept
    assert!(eq_f64(0.25, timing.duration, 0.01));
    // "cmd" was removed from the map
    assert!(!lt.get_timers().contains_key("cmd"));
}

#[test]
fn test_time_series_updates() {
    let mut ts = TimeSeries::new();

    // add a timer
    ts.add_timing(&Timing::new("cmd", 1.1, 0.25));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("cmd", 1.9, 0.51));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("cmd", 2.3, 8.8));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
            2 => vec![8.8],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("resp", 4.1, 1.0));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
            2 => vec![8.8],
        },
        "resp".to_string() => hashmap!{
            4 => vec![1.0],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // empty the series
    ts.clear();
    // construct the expected value for comparison
    let expected = hashmap!{};
    // compare
    assert_eq!(&expected, ts.get_timers());
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_correct() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        let _t = Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.25, dur, 0.001));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_wrong_binding() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        // this binding discards the value right away!
        let _ = Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.0, dur, 0.01));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_no_binding() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        // no binding means Timer does not live past the first line
        Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.0, dur, 0.01));
}
<commit_msg>relax timing test because travis<commit_after>use std::sync::mpsc;

use platform::time::sleep_secs;
use platform::time::time_now;
use testlib::cmp::eq_f64;

use super::LiveTimers;
use super::MetricsRecorder;
use super::TimeSeries;
use super::Timer;
use super::Timing;

#[test]
#[should_panic]
fn test_live_timers_name_mismatch() {
    let mut lt = LiveTimers::new();

    lt.start("cmd");
    lt.stop("resp"); // panic expected
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_live_timers_ok() {
    let mut lt = LiveTimers::new();

    let t1 = time_now();
    let start_time = lt.start("cmd");
    // start_time is very close to *now*
    assert!(eq_f64(t1, start_time, 0.01));
    // "cmd" -> start_time was added to the map
    assert_eq!(&start_time, lt.get_timers().get("cmd").unwrap());

    sleep_secs(0.25);

    let timing = lt.stop("cmd");
    // the returned start_time matches what we saw before
    assert_eq!(start_time, timing.start_time);
    // the duration is almost exactly the time we slept
    assert!(eq_f64(0.25, timing.duration, 0.01));
    // "cmd" was removed from the map
    assert!(!lt.get_timers().contains_key("cmd"));
}

#[test]
fn test_time_series_updates() {
    let mut ts = TimeSeries::new();

    // add a timer
    ts.add_timing(&Timing::new("cmd", 1.1, 0.25));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("cmd", 1.9, 0.51));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("cmd", 2.3, 8.8));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
            2 => vec![8.8],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // add another timer
    ts.add_timing(&Timing::new("resp", 4.1, 1.0));
    // construct the expected value for comparison
    let expected = hashmap!{
        "cmd".to_string() => hashmap!{
            1 => vec![0.25, 0.51],
            2 => vec![8.8],
        },
        "resp".to_string() => hashmap!{
            4 => vec![1.0],
        },
    };
    // compare
    assert_eq!(&expected, ts.get_timers());

    // empty the series
    ts.clear();
    // construct the expected value for comparison
    let expected = hashmap!{};
    // compare
    assert_eq!(&expected, ts.get_timers());
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_correct() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        let _t = Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.25, dur, 0.01));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_wrong_binding() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        // this binding discards the value right away!
        let _ = Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.0, dur, 0.01));
}

// this is a slow test that relies on sleeps
#[ignore]
#[test]
fn test_timer_no_binding() {
    let (met_tx, met_rx) = mpsc::channel();
    let mut rec = MetricsRecorder::new(met_tx, true);

    // use Timer to make one timing
    let _rv = {
        // no binding means Timer does not live past the first line
        Timer::new(&mut rec, "cmd");
        sleep_secs(0.25);
        ()
    };

    // flush the metrics so we can see them
    rec.flush_metrics();

    // receive the metrics
    let metrics = met_rx.recv().unwrap();
    // verify that the timing is correct
    let dur = metrics.first().get_timing().duration;
    assert!(eq_f64(0.0, dur, 0.01));
}
<|endoftext|>


<commit_before>//! Structures for the Patch and Data servers.

use std::net::{TcpListener, TcpStream, SocketAddrV4};
use std::io;
use std::borrow::Borrow;
use std::thread;
use std::string::ToString;

use psocrypto::pc::PcCipher;
use psocrypto::{DecryptReader, EncryptWriter};

use psomsg::Serial;

use rand::random;

pub struct PatchServer {
    motd_template: String,
    bind: String,
    data_servers: Vec<SocketAddrV4>
}

pub struct DataServer {
    bind: String
}

pub struct ClientContext {
    stream: TcpStream,
    motd: String,
    data_addr: Option<SocketAddrV4>
}

impl ClientContext {
    pub fn run(&mut self) -> () {
        use psomsg::patch::*;

        let peer_addr = self.stream.peer_addr().unwrap();

        info!("[{}] connected", peer_addr);

        let server_cipher = PcCipher::new(random());
        let client_cipher = PcCipher::new(random());

        let w = Message::Welcome(Some(Welcome {
            server_vector: server_cipher.seed(),
            client_vector: client_cipher.seed()
        }));
        if let Err(e) = w.serialize(&mut self.stream) {
            error!("unable to send welcome message to {}: {}", peer_addr, e);
        }
        info!("[{}] welcomed", peer_addr);

        // now wrap our stream in crypto
        let mut w_s = EncryptWriter::new(self.stream.try_clone().unwrap(), server_cipher);
        let mut r_s = DecryptReader::new(self.stream.try_clone().unwrap(), client_cipher);

        // Client will send a Welcome message as an ack. We reply with a Login ack.
        if let Ok(s) = Message::deserialize(&mut r_s) {
            if let Message::Welcome(None) = s {
                info!("[{}] responded to welcome", peer_addr);
                match Message::Login(None).serialize(&mut w_s) { Err(_) => return, _ => () }
            }
        }

        loop {
            // Read message
            if let Ok(s) = Message::deserialize(&mut r_s) {match s {
                Message::Login(Some(_)) => {
                    info!("[{}] logged in, sending motd and redirecting", peer_addr);
                    let motd = Message::Motd(Some(Motd {
                        message: self.motd.clone()
                    }));
                    motd.serialize(&mut w_s).unwrap();
                    let red = Message::Redirect(Some(Redirect(self.data_addr.as_ref().unwrap().clone())));
                    red.serialize(&mut w_s).unwrap();
                    // Now we break out of this connection.
                    return;
                },
                u => {error!("unexpected message received, exiting: {:?}", u); return}
            }}
        };
    }

    pub fn run_data(&mut self) -> () {
        use psomsg::patch::*;
        use staticvec::StaticVec;
        let peer = self.stream.peer_addr().unwrap();

        info!("connected {}", peer);

        let server_cipher = PcCipher::new(random());
        let client_cipher = PcCipher::new(random());

        let w = Message::Welcome(Some(Welcome {
            client_vector: client_cipher.seed(),
            server_vector: server_cipher.seed()
        }));
        w.serialize(&mut self.stream).unwrap();

        // now wrap our stream in crypto
        let mut w_s = EncryptWriter::new(self.stream.try_clone().unwrap(), server_cipher);
        let mut r_s = DecryptReader::new(self.stream.try_clone().unwrap(), client_cipher);

        if let Ok(Message::Welcome(None)) = Message::deserialize(&mut r_s) {
            Message::Login(None).serialize(&mut w_s).unwrap();
        }

        loop {
            let m = Message::deserialize(&mut r_s);
            if let Ok(m) = m {match m {
                Message::Login(Some(_)) => {
                    Message::StartList(None).serialize(&mut w_s).unwrap();
                    Message::SetDirectory(Some(SetDirectory { dirname: StaticVec::default() })).serialize(&mut w_s).unwrap();
                    Message::InfoFinished(None).serialize(&mut w_s).unwrap();
                },
                Message::FileListDone(_) => {
                    Message::SetDirectory(Some(SetDirectory { dirname: StaticVec::default() })).serialize(&mut w_s).unwrap();
                    Message::OneDirUp(None).serialize(&mut w_s).unwrap();
                    Message::SendDone(None).serialize(&mut w_s).unwrap();
                    info!("client {} was 'updated' successfully", peer);
                }
                e => error!("recv something else! {:?}", e)
            }} else {
                return
            }
        }
    }
}

unsafe impl Send for ClientContext {}

impl PatchServer {
    pub fn new_bb<T: ToString, B: ToString>(motd_template: T, bind: B, data_servers: &[SocketAddrV4]) -> PatchServer {
        PatchServer {
            motd_template: motd_template.to_string(),
            bind: bind.to_string(),
            data_servers: data_servers.to_owned()
        }
    }

    pub fn format_motd(&self, client_num: u32) -> String {
        let motd = self.motd_template.replace("{client_num}", &format!("{}", client_num));
        motd
    }

    /// Runs the patch server, moving this value. This method will block until the server
    /// concludes.
    pub fn run(self) -> io::Result<()> {
        let bind_addr = self.bind.clone(); // borrow checker just in case
        let tcp_listener = try!(TcpListener::bind(bind_addr.borrow() as &str));

        let mut total_connects = 0;

        for s in tcp_listener.incoming() {
            match s {
                Ok(s) => {
                    total_connects += 1;
                    let mut ctx = ClientContext {
                        stream: s,
                        motd: self.format_motd(total_connects),
                        data_addr: Some(self.data_servers[random::<usize>() % self.data_servers.len()])
                    };

                    thread::spawn(move || {ctx.run();});
                },
                Err(e) => {
                    return Err(e)
                }
            }
        }
        Ok(())
    }
}

impl DataServer {
    pub fn new_bb<B: ToString>(bind: B) -> DataServer {
        DataServer {
            bind: bind.to_string()
        }
    }

    pub fn run(self) -> io::Result<()> {
        let bind_addr = self.bind.clone(); // borrow checker just in case
        let tcp_listener = try!(TcpListener::bind(bind_addr.borrow() as &str));

        for s in tcp_listener.incoming() {
            match s {
                Ok(s) => {
                    let mut ctx = ClientContext {
                        stream: s,
                        motd: "".to_string(),
                        data_addr: None
                    };

                    thread::spawn(move || {ctx.run_data();});
                },
                Err(e) => {
                    return Err(e)
                }
            }
        }
        Ok(())
    }
}
<commit_msg>Remove old patch server code.<commit_after><|endoftext|>


<commit_before>//! Abstraction of spatial partitioning schemes

pub use partition::interval::Interval;
pub use partition::boxes::{Box2, Box3};
pub use partition::ncube::Ncube;
pub use partition::unitquad::UnitQuad;

#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::TestResult;

/// A type that can be subdivided
pub trait Subdivide {
    /// Subdivide into smaller partitions
    fn subdivide(&self) -> Vec<Self>;
}

/// A type describing a partition of some space
///
/// In addition to this trait signature an implementation is required to satisfy
/// `prop_is_total`.
pub trait Partition<T>: Subdivide + Sized {
    /// Does the partition contain an element?
    fn contains(&self, elem: &T) -> bool;

    /// Dispatch an element to the correct subpartition
    ///
    /// The default implementation works, if the totality proposition is
    /// fulfilled. However, note that its performance is not optimal, as it
    /// checks for all subpartitions whether they contain the element, until one
    /// is found that does.
    fn dispatch(&self, elem: &T) -> usize {
        for (i, part) in self.subdivide().iter().enumerate() {
            if part.contains(elem) {
                return i;
            }
        }
        panic!("partition dispatch impossible");
    }
}

/// Totality proposition (contained)
///
/// Any element contained in the partition will be contained in exactly one of
/// its subpartitions.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(
            partition.subdivide().iter()
                .filter(|sub| sub.contains(&elem)).count()
            == 1
        )
    }
    else {
        TestResult::discard()
    }
}

/// Totality proposition (not contained)
///
/// If a partition does not contain an element, none of its subpartitions
/// contain it either.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_non_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::discard()
    }
    else {
        TestResult::from_bool(
            partition.subdivide().iter()
                .all(|sub| !sub.contains(&elem))
        )
    }
}

/// Consistency of dispatch mechanism
///
/// An element contained in the partition must be dispatched consistently, i.e.
/// the subpartition to which it is dispatched must contain it.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_consistent_dispatch<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(partition.subdivide()[partition.dispatch(&elem)].contains(&elem))
    }
    else {
        TestResult::discard()
    }
}

#[macro_escape]
macro_rules! partition_quickcheck (
    ($testfn: ident, $p: ty, $t: ty) => (
        mod $testfn {
            use $crate::partition::{
                prop_is_total_elem, prop_is_total_non_elem,
                prop_consistent_dispatch
            };
            use quickcheck::{quickcheck, TestResult};
            use super::*;

            #[test]
            fn is_total_elem() {
                quickcheck(prop_is_total_elem as fn($p, $t) -> TestResult);
            }

            #[test]
            fn is_total_non_elem() {
                quickcheck(prop_is_total_non_elem as fn($p, $t) -> TestResult);
            }

            #[test]
            fn consistent_dispatch() {
                quickcheck(prop_consistent_dispatch as fn($p, $t) -> TestResult);
            }
        }
    )
);

/// The notion of a mid point between two inputs
trait Mid {
    /// Return the mid between this point and another
    fn mid(&self, other: &Self) -> Self;
}

impl Mid for f64 {
    fn mid(&self, other: &f64) -> f64 { (*self + *other) / 2.0 }
}

impl Mid for f32 {
    fn mid(&self, other: &f32) -> f32 { (*self + *other) / 2.0 }
}

mod interval;
mod boxes;
mod ncube;
mod unitquad;
pub mod cubemap;
<commit_msg>Resolve type ambiguity<commit_after>//! Abstraction of spatial partitioning schemes

pub use partition::interval::Interval;
pub use partition::boxes::{Box2, Box3};
pub use partition::ncube::Ncube;
pub use partition::unitquad::UnitQuad;

#[cfg(any(test, feature = "arbitrary"))]
use quickcheck::TestResult;

/// A type that can be subdivided
pub trait Subdivide {
    /// Subdivide into smaller partitions
    fn subdivide(&self) -> Vec<Self>;
}

/// A type describing a partition of some space
///
/// In addition to this trait signature an implementation is required to satisfy
/// `prop_is_total`.
pub trait Partition<T>: Subdivide + Sized {
    /// Does the partition contain an element?
    fn contains(&self, elem: &T) -> bool;

    /// Dispatch an element to the correct subpartition
    ///
    /// The default implementation works, if the totality proposition is
    /// fulfilled. However, note that its performance is not optimal, as it
    /// checks for all subpartitions whether they contain the element, until one
    /// is found that does.
    fn dispatch(&self, elem: &T) -> usize {
        for (i, part) in self.subdivide().iter().enumerate() {
            if part.contains(elem) {
                return i;
            }
        }
        panic!("partition dispatch impossible");
    }
}

/// Totality proposition (contained)
///
/// Any element contained in the partition will be contained in exactly one of
/// its subpartitions.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(
            partition.subdivide().iter()
                .filter(|sub| sub.contains(&elem)).count()
            == 1
        )
    }
    else {
        TestResult::discard()
    }
}

/// Totality proposition (not contained)
///
/// If a partition does not contain an element, none of its subpartitions
/// contain it either.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_is_total_non_elem<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::discard()
    }
    else {
        TestResult::from_bool(
            partition.subdivide().iter()
                .all(|sub| !sub.contains(&elem))
        )
    }
}

/// Consistency of dispatch mechanism
///
/// An element contained in the partition must be dispatched consistently, i.e.
/// the subpartition to which it is dispatched must contain it.
#[cfg(any(test, feature = "arbitrary"))]
pub fn prop_consistent_dispatch<P: Partition<T>, T>(partition: P, elem: T) -> TestResult {
    if partition.contains(&elem) {
        TestResult::from_bool(partition.subdivide()[partition.dispatch(&elem)].contains(&elem))
    }
    else {
        TestResult::discard()
    }
}

#[macro_escape]
macro_rules! partition_quickcheck (
    ($testfn: ident, $p: ty, $t: ty) => (
        mod $testfn {
            use $crate::partition::{
                prop_is_total_elem, prop_is_total_non_elem,
                prop_consistent_dispatch
            };
            use quickcheck::{quickcheck, TestResult};
            use super::*;

            #[test]
            fn is_total_elem() {
                quickcheck(prop_is_total_elem::<$p, $t> as fn($p, $t) -> TestResult);
            }

            #[test]
            fn is_total_non_elem() {
                quickcheck(prop_is_total_non_elem::<$p, $t> as fn($p, $t) -> TestResult);
            }

            #[test]
            fn consistent_dispatch() {
                quickcheck(prop_consistent_dispatch::<$p, $t> as fn($p, $t) -> TestResult);
            }
        }
    )
);

/// The notion of a mid point between two inputs
trait Mid {
    /// Return the mid between this point and another
    fn mid(&self, other: &Self) -> Self;
}

impl Mid for f64 {
    fn mid(&self, other: &f64) -> f64 { (*self + *other) / 2.0 }
}

impl Mid for f32 {
    fn mid(&self, other: &f32) -> f32 { (*self + *other) / 2.0 }
}

mod interval;
mod boxes;
mod ncube;
mod unitquad;
pub mod cubemap;
<|endoftext|>


<commit_before>use std::cmp::{Eq, PartialEq, Ordering, PartialOrd};
use rand::Rng;
use rand::distributions::{IndependentSample, Range};

fn schwefel(solution: &Vec<f64>) -> f64 {
    418.9829_f64 * solution.len() as f64
        + solution.iter().fold(0_f64, |sum, x| sum + x * x.abs().sqrt().sin())
}

pub struct Individual {
    pub solution: Vec<f64>,
    pub fitness: f64,
}

impl Individual {
    pub fn new<R: Rng>(range: &Range<f64>, rng: &mut R) -> Self {
        let solution = (0..50).map(|_| range.ind_sample(rng)).collect();
        let fitness = schwefel(&solution);

        Individual { solution: solution, fitness: fitness }
    }

    pub fn mutate<R: Rng>(&mut self, range: &Range<f64>, rng: &mut R) {
        for x in &mut self.solution {
            if rng.gen_weighted_bool(40) {
                *x = range.ind_sample(rng)
            }
        }
        self.fitness = schwefel(&self.solution);
    }
}

impl Clone for Individual {
    fn clone(&self) -> Self {
        Individual { solution: self.solution.clone(), fitness: self.fitness }
    }
}

impl Eq for Individual {}

impl Ord for Individual {
    /// This dangerously delegates to `partial_cmp`
    fn cmp(&self, other: &Self) -> Ordering {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result;
        }
        unimplemented!();
    }
}

impl PartialEq<Individual> for Individual {
    /// This doesn't use `fitness.eq()` because it needs to be
    /// consistent with `Eq`
    fn eq(&self, other: &Individual) -> bool {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result == Ordering::Equal;
        }
        unimplemented!();
    }
}

impl PartialOrd for Individual {
    /// This delegates to `fitness.partial_cmp()`
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.fitness.partial_cmp(&other.fitness)
    }
}
<commit_msg>Implement a messy two-point crossover<commit_after>use std::cmp::{Eq, PartialEq, Ordering, PartialOrd};
use std::mem;
use rand::Rng;
use rand::distributions::{IndependentSample, Range};

fn schwefel(solution: &Vec<f64>) -> f64 {
    418.9829_f64 * solution.len() as f64
        + solution.iter().fold(0_f64, |sum, x| sum + x * x.abs().sqrt().sin())
}

pub struct Individual {
    pub solution: Vec<f64>,
    pub fitness: f64,
}

impl Individual {
    pub fn new<R: Rng>(range: &Range<f64>, rng: &mut R) -> Self {
        let solution = (0..50).map(|_| range.ind_sample(rng)).collect();
        let fitness = schwefel(&solution);

        Individual { solution: solution, fitness: fitness }
    }

    pub fn mutate<R: Rng>(&mut self, range: &Range<f64>, rng: &mut R) {
        for x in &mut self.solution {
            if rng.gen_weighted_bool(40) {
                *x = range.ind_sample(rng)
            }
        }
        self.fitness = schwefel(&self.solution);
    }

    pub fn combine<R: Rng>(x: &mut Individual, y: &mut Individual, rng: &mut R) {
        if rng.gen_weighted_bool(2) {
            let len = x.solution.len();
            let (begin, n) = (rng.gen_range(0, len), rng.gen_range(0, len));
            for i in begin..((begin + n) % len) {
                mem::swap(&mut x.solution[i], &mut y.solution[i]);
            }
            x.fitness = schwefel(&x.solution);
            y.fitness = schwefel(&y.solution);
        }
    }
}

impl Clone for Individual {
    fn clone(&self) -> Self {
        Individual { solution: self.solution.clone(), fitness: self.fitness }
    }
}

impl Eq for Individual {}

impl Ord for Individual {
    /// This dangerously delegates to `partial_cmp`
    fn cmp(&self, other: &Self) -> Ordering {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result;
        }
        unimplemented!();
    }
}

impl PartialEq<Individual> for Individual {
    /// This doesn't use `fitness.eq()` because it needs to be
    /// consistent with `Eq`
    fn eq(&self, other: &Individual) -> bool {
        if let Some(result) = self.fitness.partial_cmp(&other.fitness) {
            return result == Ordering::Equal;
        }
        unimplemented!();
    }
}

impl PartialOrd for Individual {
    /// This delegates to `fitness.partial_cmp()`
    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
        self.fitness.partial_cmp(&other.fitness)
    }
}
<|endoftext|>


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

//! Tests for ioreg! syntax extension

#![feature(phase)]
#[phase(plugin)] extern crate macro_ioreg;
#[phase(plugin,link)] extern crate shiny;
extern crate core;

#[path="../zinc/util/volatile_cell.rs"] mod volatile_cell;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use std::ptr::RawPtr;
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: uint) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as int))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  })

  describe!(
    before_each {
      let test: BASIC_TEST = zeroed_safe();
    }

    it "can round_trip simple field values 1" {
      test.reg1.set_field1(true);
      assert_eq!(test.reg1.field1(), true)
      assert_eq!(get_value(&test, 0), 1)
      assert_eq!(get_value(&test, 1), 0)
    }

    it "can round trip simple field values 2" {
      test.reg1.set_field3(0xde);
      assert_eq!(test.reg1.field3(), 0xde)
      assert_eq!(get_value(&test, 0), 0xde<<16)
    }

    it "sets set_to_clear fields" {
      test.reg1.clear_field4();
      assert_eq!(get_value(&test, 0), 1<<25)
    }

    it "does not read from writeonly registers" {
      test.wo_reg.set_field1(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead);
      test.wo_reg.set_field2(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead<<16);
    }
  )

  ioregs!(GROUP_TEST = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  })

  describe!(
    before_each {
      let test: GROUP_TEST = zeroed_safe();
    }

    it "sets groups correctly" {
      test.regs[0].reg1.set_field1(0xdeadbeef);
      assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef)
      assert_eq!(get_value(&test, 0), 0xdeadbeef)
      for i in range(1, 10) {
        assert_eq!(get_value(&test, i), 0)
      }

      test.regs[2].reg2.set_field2(0xfeedbeef);
      assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef)
      assert_eq!(get_value(&test, 5), 0xfeedbeef)
    }
  )

  ioregs!(FIELD_ARRAY_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  })

  describe!(
    before_each {
      let test: FIELD_ARRAY_TEST = zeroed_safe();
    }

    it "sets field arrays correctly" {
      test.reg1.set_field(0, 1);
      assert_eq!(test.reg1.field(0), 1);
      assert_eq!(get_value(&test, 0), 0x1)

      test.reg1.set_field(4, 3);
      assert_eq!(test.reg1.field(4), 3);
      assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8)
    }
  )
}
<commit_msg>ioreg::test: Test gap offset<commit_after>// Zinc, the bare metal stack for rust.
// Copyright 2014 Ben Gamari <bgamari@gmail.com>
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Tests for ioreg! syntax extension

#![feature(phase)]
#[phase(plugin)] extern crate macro_ioreg;
#[phase(plugin,link)] extern crate shiny;
extern crate core;

#[path="../zinc/util/volatile_cell.rs"] mod volatile_cell;

#[cfg(test)]
mod test {
  use std::mem::{transmute, zeroed};
  use std::ptr::RawPtr;
  use volatile_cell::VolatileCell;

  fn get_value<'a, T>(v: &'a T, offset: uint) -> u32 {
    unsafe {
      let ptr: *const u32 = transmute(v);
      *(ptr.offset(offset as int))
    }
  }

  fn zeroed_safe<T: Copy>() -> T {
    unsafe {
      return zeroed();
    }
  }

  ioregs!(BASIC_TEST = {
    0x0 => reg32 reg1 {
      0      => field1,
      1..3   => field2,
      16..24 => field3,
      25     => field4: set_to_clear,
    }
    0x4 => reg32 reg2 {
      0      => field1,
    }
    0x8 => reg32 wo_reg {
      0..15  => field1: wo,
      16..31 => field2: wo,
    }
  })

  describe!(
    before_each {
      let test: BASIC_TEST = zeroed_safe();
    }

    it "can round_trip simple field values 1" {
      test.reg1.set_field1(true);
      assert_eq!(test.reg1.field1(), true)
      assert_eq!(get_value(&test, 0), 1)
      assert_eq!(get_value(&test, 1), 0)
    }

    it "can round trip simple field values 2" {
      test.reg1.set_field3(0xde);
      assert_eq!(test.reg1.field3(), 0xde)
      assert_eq!(get_value(&test, 0), 0xde<<16)
    }

    it "sets set_to_clear fields" {
      test.reg1.clear_field4();
      assert_eq!(get_value(&test, 0), 1<<25)
    }

    it "does not read from writeonly registers" {
      test.wo_reg.set_field1(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead);
      test.wo_reg.set_field2(0xdead);
      assert_eq!(get_value(&test, 2), 0xdead<<16);
    }
  )

  ioregs!(GROUP_TEST = {
    0x0 => group regs[5] {
      0x0 => reg32 reg1 {
        0..31 => field1
      }
      0x4 => reg32 reg2 {
        0..31 => field2
      }
    }
  })

  describe!(
    before_each {
      let test: GROUP_TEST = zeroed_safe();
    }

    it "sets groups correctly" {
      test.regs[0].reg1.set_field1(0xdeadbeef);
      assert_eq!(test.regs[0].reg1.field1(), 0xdeadbeef)
      assert_eq!(get_value(&test, 0), 0xdeadbeef)
      for i in range(1, 10) {
        assert_eq!(get_value(&test, i), 0)
      }

      test.regs[2].reg2.set_field2(0xfeedbeef);
      assert_eq!(test.regs[2].reg2.field2(), 0xfeedbeef)
      assert_eq!(get_value(&test, 5), 0xfeedbeef)
    }
  )

  ioregs!(FIELD_ARRAY_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field[16]
    }
  })

  describe!(
    before_each {
      let test: FIELD_ARRAY_TEST = zeroed_safe();
    }

    it "sets field arrays correctly" {
      test.reg1.set_field(0, 1);
      assert_eq!(test.reg1.field(0), 1);
      assert_eq!(get_value(&test, 0), 0x1)

      test.reg1.set_field(4, 3);
      assert_eq!(test.reg1.field(4), 3);
      assert_eq!(get_value(&test, 0), 0x1 | 0x3<<8)
    }
  )

  ioregs!(GAP_TEST = {
    0x0 => reg32 reg1 {
      0..31 => field,
    }
    0x10 => reg32 reg2 {
      0..31 => field,
    }
    0x14 => reg32 reg3 {
      0..31 => field,
    }
    0x20 => reg32 reg4 {
      0..31 => field,
    }
  })

  describe!(
    before_each {
      let test: GAP_TEST = zeroed_safe();
      let base = &test as *const GAP_TEST;
    }
    it "has zero base offset" {
      let addr = &test.reg1 as *const GAP_TEST_reg1;
      assert_eq!(addr.to_uint() - base.to_uint(), 0x0)
    }
    it "computes the correct first gap" {
      let addr = &test.reg2 as *const GAP_TEST_reg2;
      assert_eq!(addr.to_uint() - base.to_uint(), 0x10)
    }
    it "computes the correct second gap" {
      let addr = &test.reg4 as *const GAP_TEST_reg4;
      assert_eq!(addr.to_uint() - base.to_uint(), 0x20)
    }
  )
}
<|endoftext|>


<commit_before>use term;

use std::convert::AsRef;
use std::io;
use std::io::Write;
use std::fmt::Display;

/// The level of information to display to a logger
///
/// This enum should only be used as parameters for `Logger` or `Book` methods. Library
/// users should **not** do exhaustive pattern matching on the variants of the enums,
/// as it might grow variants later.
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
pub enum InfoLevel {
    /// Debug: the lowest level
    Debug = 0,
    /// Warning: won't be displayed by default
    Warning,
    /// Info: won't be displayed by default
    Info,
    /// Error
    Error,
    /// Quiet
    Quiet,

    /// Hint that destructuring should not be exhaustive
    #[doc(hidden)]
    __NonExhaustive,
}

use self::InfoLevel::*;

/// Abstract over eithr term outupt or (if it fails) io::stderr()
enum Output {
    Terminal(Box<term::StderrTerminal>),
    Stderr(io::Stderr),
}

impl Output {
    pub fn new() -> Output {
        if let Some(term) = term::stderr() {
            if term.supports_color() {
                return Output::Terminal(term)
            }
        }
        return Output::Stderr(io::stderr())
    }

    pub fn print_msg<S: Display>(&mut self, level: InfoLevel, msg: S) {
        let (colour, head_msg) = match level {
            Debug => (term::color::BRIGHT_BLUE, lformat!("Debug: ")),
            Warning => (term::color::BRIGHT_YELLOW, lformat!("Warning: ")),
            Info => (term::color::BRIGHT_GREEN, lformat!("Info: ")),
            Error => (term::color::BRIGHT_RED, lformat!("Error: ")),
            _ => unreachable!(),
        };
        match *self {
            Output::Stderr(ref mut stderr) => {
                writeln!(stderr, "{}{}",
                       head_msg,
                       msg)
                    .unwrap();
            },
            Output::Terminal(ref mut term) => {
                term.fg(colour)
                    .unwrap();
                term.attr(term::Attr::Bold)
                    .unwrap();
                write!(term, "{}",
                       head_msg)
                    .unwrap();
                term.reset()
                    .unwrap();
                writeln!(term, "{}",
                       msg)
                    .unwrap();
            }
        }
    }
}

/// Logs info and warning message and choose whether to display them
/// according to verbosity
#[derive(Debug)]
pub struct Logger {
    verbosity: InfoLevel,
}

impl Logger {
    /// Creates a new logger with defined verbosity
    pub fn new(verbosity: InfoLevel) -> Logger {
        Logger { verbosity: verbosity }
    }

    /// Sets verbosity
    pub fn set_verbosity(&mut self, verbosity: InfoLevel) {
        self.verbosity = verbosity;
    }

    /// Prints a message
    pub fn display_msg<S: AsRef<str>>(level: InfoLevel, s: S) {
        let mut output = Output::new();
        output.print_msg(level, s.as_ref());
    }

    /// Prints a debug message
    pub fn display_debug<S: AsRef<str>>(s: S) {
        Self::display_msg(Debug, s);
    }

    /// Prints an info message
    pub fn display_info<S: AsRef<str>>(s: S) {
        Self::display_msg(Info, s);
    }

    /// Prints a warning message
    pub fn display_warning<S: AsRef<str>>(s: S) {
        Self::display_msg(Warning, s);
    }

    /// Prints an error message
    pub fn display_error<S: AsRef<str>>(s: S) {
        Self::display_msg(Error, s);
    }

    /// Prints a message if logger's verbosity <= level
    pub fn log<S: AsRef<str>>(&self, level: InfoLevel, s: S) {
        if level >= self.verbosity {
            match level {
                Debug => Self::display_debug(s),
                Info => Self::display_info(s),
                Warning => Self::display_warning(s),
                Error => Self::display_error(s),
                Quiet => unreachable!(),
                __NonExhaustive => unreachable!(),
            }
        }
    }

    /// Equivalent of log(Debug, s)
    pub fn debug<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Debug, s);
    }

    /// Equivalent of log(Info, s)
    pub fn info<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Info, s);
    }

    /// Equivalent of log(Warning, s)
    pub fn warning<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Warning, s);
    }

    /// Equivalent of log(Error, s)
    pub fn error<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Error, s);
    }
}

// Code to end shell colouring
pub const SHELL_COLOUR_OFF: &'static str = "\x1B[0m";
pub const SHELL_COLOUR_RED: &'static str = "\x1B[1m\x1B[31m";
pub const SHELL_COLOUR_BLUE: &'static str = "\x1B[1m\x1B[36m";
pub const SHELL_COLOUR_ORANGE: &'static str = "\x1B[1m\x1B[33m";
pub const SHELL_COLOUR_GREEN: &'static str = "\x1B[1m\x1B[32m";
<commit_msg>Try to build on windows<commit_after>use term;

use std::convert::AsRef;
use std::io;
use std::io::Write;
use std::fmt::Display;

/// The level of information to display to a logger
///
/// This enum should only be used as parameters for `Logger` or `Book` methods. Library
/// users should **not** do exhaustive pattern matching on the variants of the enums,
/// as it might grow variants later.
#[derive(Debug, PartialEq, Eq, PartialOrd, Clone, Copy)]
pub enum InfoLevel {
    /// Debug: the lowest level
    Debug = 0,
    /// Warning: won't be displayed by default
    Warning,
    /// Info: won't be displayed by default
    Info,
    /// Error
    Error,
    /// Quiet
    Quiet,

    /// Hint that destructuring should not be exhaustive
    #[doc(hidden)]
    __NonExhaustive,
}

use self::InfoLevel::*;

/// Abstract over eithr term outupt or (if it fails) io::stderr()
enum Output {
    Terminal(Box<term::StderrTerminal>),
    Stderr(io::Stderr),
}

impl Output {
    pub fn new() -> Output {
        if let Some(term) = term::stderr() {
            if (*term).supports_color() {
                return Output::Terminal(term)
            }
        }
        return Output::Stderr(io::stderr())
    }

    pub fn print_msg<S: Display>(&mut self, level: InfoLevel, msg: S) {
        let (colour, head_msg) = match level {
            Debug => (term::color::BRIGHT_BLUE, lformat!("Debug: ")),
            Warning => (term::color::BRIGHT_YELLOW, lformat!("Warning: ")),
            Info => (term::color::BRIGHT_GREEN, lformat!("Info: ")),
            Error => (term::color::BRIGHT_RED, lformat!("Error: ")),
            _ => unreachable!(),
        };
        match *self {
            Output::Stderr(ref mut stderr) => {
                writeln!(stderr, "{}{}",
                       head_msg,
                       msg)
                    .unwrap();
            },
            Output::Terminal(ref mut term) => {
                term.fg(colour)
                    .unwrap();
                term.attr(term::Attr::Bold)
                    .unwrap();
                write!(term, "{}",
                       head_msg)
                    .unwrap();
                term.reset()
                    .unwrap();
                writeln!(term, "{}",
                       msg)
                    .unwrap();
            }
        }
    }
}

/// Logs info and warning message and choose whether to display them
/// according to verbosity
#[derive(Debug)]
pub struct Logger {
    verbosity: InfoLevel,
}

impl Logger {
    /// Creates a new logger with defined verbosity
    pub fn new(verbosity: InfoLevel) -> Logger {
        Logger { verbosity: verbosity }
    }

    /// Sets verbosity
    pub fn set_verbosity(&mut self, verbosity: InfoLevel) {
        self.verbosity = verbosity;
    }

    /// Prints a message
    pub fn display_msg<S: AsRef<str>>(level: InfoLevel, s: S) {
        let mut output = Output::new();
        output.print_msg(level, s.as_ref());
    }

    /// Prints a debug message
    pub fn display_debug<S: AsRef<str>>(s: S) {
        Self::display_msg(Debug, s);
    }

    /// Prints an info message
    pub fn display_info<S: AsRef<str>>(s: S) {
        Self::display_msg(Info, s);
    }

    /// Prints a warning message
    pub fn display_warning<S: AsRef<str>>(s: S) {
        Self::display_msg(Warning, s);
    }

    /// Prints an error message
    pub fn display_error<S: AsRef<str>>(s: S) {
        Self::display_msg(Error, s);
    }

    /// Prints a message if logger's verbosity <= level
    pub fn log<S: AsRef<str>>(&self, level: InfoLevel, s: S) {
        if level >= self.verbosity {
            match level {
                Debug => Self::display_debug(s),
                Info => Self::display_info(s),
                Warning => Self::display_warning(s),
                Error => Self::display_error(s),
                Quiet => unreachable!(),
                __NonExhaustive => unreachable!(),
            }
        }
    }

    /// Equivalent of log(Debug, s)
    pub fn debug<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Debug, s);
    }

    /// Equivalent of log(Info, s)
    pub fn info<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Info, s);
    }

    /// Equivalent of log(Warning, s)
    pub fn warning<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Warning, s);
    }

    /// Equivalent of log(Error, s)
    pub fn error<S: AsRef<str>>(&self, s: S) {
        self.log(InfoLevel::Error, s);
    }
}

// Code to end shell colouring
pub const SHELL_COLOUR_OFF: &'static str = "\x1B[0m";
pub const SHELL_COLOUR_RED: &'static str = "\x1B[1m\x1B[31m";
pub const SHELL_COLOUR_BLUE: &'static str = "\x1B[1m\x1B[36m";
pub const SHELL_COLOUR_ORANGE: &'static str = "\x1B[1m\x1B[33m";
pub const SHELL_COLOUR_GREEN: &'static str = "\x1B[1m\x1B[32m";
<|endoftext|>


<commit_before>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rwinstructs::guid::{Guid};
use rshellitems::shelllist::{ShellList};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::datablocks::{ExtraDataBlocks};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::Read;
use std::io::{Seek,SeekFrom};

#[derive(Serialize,Debug)]
// 76 bytes long,
pub struct ShellLinkHeader {
    #[serde(skip_serializing)]
    _offset: u64,
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    #[serde(skip_serializing)]
    pub unknown1: u16,
    #[serde(skip_serializing)]
    pub unknown2: u32,
    #[serde(skip_serializing)]
    pub unknown3: u32
}
impl ShellLinkHeader {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<ShellLinkHeader,LnkError> {
        let _offset = reader.seek(SeekFrom::Current(0))?;
        let header_size = reader.read_u32::<LittleEndian>()?;
        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            ShellLinkHeader {
                _offset: _offset,
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Serialize,Debug)]
pub struct TargetIdList {
    #[serde(skip_serializing)]
    _offset: u64,
    pub list_size: u16,
    pub shell_items: ShellList
}

impl TargetIdList{
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<TargetIdList, LnkError> {
        let _offset = reader.seek(SeekFrom::Current(0))?;
        let list_size = reader.read_u16::<LittleEndian>()?;

        let shell_items = ShellList::new(
            &mut reader
        )?;

        Ok(
            TargetIdList {
                _offset: _offset,
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Serialize,Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Lnk {
    pub header: ShellLinkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings,
    pub extra_data: ExtraDataBlocks
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        let header = ShellLinkHeader::new(&mut reader)?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            target_list = Some(
                TargetIdList::new(&mut reader)?
            );
        }

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            location_info = Some(
                LocationInfo::new(&mut reader)?
            );
        }

        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        let extra_data = ExtraDataBlocks::new(
            &mut reader
        )?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings,
                extra_data: extra_data
            }
        )
    }
}
<commit_msg>LNK validations<commit_after>use byteorder::{ReadBytesExt, LittleEndian};
use rwinstructs::timestamp::{WinTimestamp};
use rwinstructs::guid::{Guid};
use rshellitems::shelllist::{ShellList};
use lnkpkg::locationinfo::{LocationInfo};
use lnkpkg::datablocks::{ExtraDataBlocks};
use lnkpkg::flags::{DataFlags,FileFlags};
use lnkpkg::flags;
use lnkpkg::errors::{LnkError};
use lnkpkg::utils;
use std::io::Read;
use std::io::{Seek,SeekFrom};

#[derive(Serialize,Debug)]
// 76 bytes long,
pub struct LnkHeader {
    #[serde(skip_serializing)]
    _offset: u64,
    pub header_size: u32,
    pub guid: Guid,
    pub data_flags: DataFlags,
    pub file_flags: FileFlags,
    pub created: WinTimestamp,
    pub accessed: WinTimestamp,
    pub modified: WinTimestamp,
    pub file_size: u32,
    pub icon_offset: i32,
    pub window_flag: u32,
    pub hot_key: u16,
    #[serde(skip_serializing)]
    pub unknown1: u16,
    #[serde(skip_serializing)]
    pub unknown2: u32,
    #[serde(skip_serializing)]
    pub unknown3: u32
}
impl LnkHeader {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<LnkHeader,LnkError> {
        let _offset = reader.seek(SeekFrom::Current(0))?;
        let header_size = reader.read_u32::<LittleEndian>()?;
        if header_size != 76 {
            return Err(
                LnkError::validation_error(
                    format!("Header size unhandled. Got {}, expected 76.",header_size)
                )
            );
        }

        let mut guid = Guid([0; 16]);
        reader.read_exact(&mut guid.0)?;

        // Do a GUID check
        if guid.to_string() != "00021401-0000-0000-C000-000000000046" {
            return Err(
                LnkError::validation_error(
                    format!(
                        "GUID {} is not the known LNK GUID of 00021401-0000-0000-C000-000000000046",
                        guid.to_string()
                    )
                )
            );
        }

        let data_flags = DataFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );

        let file_flags = FileFlags::from_bits_truncate(
            reader.read_u32::<LittleEndian>()?
        );
        let created = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let accessed = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let modified = WinTimestamp(reader.read_u64::<LittleEndian>()?);
        let file_size = reader.read_u32::<LittleEndian>()?;
        let icon_offset = reader.read_i32::<LittleEndian>()?;
        let window_flag = reader.read_u32::<LittleEndian>()?;
        let hot_key = reader.read_u16::<LittleEndian>()?;
        let unknown1 = reader.read_u16::<LittleEndian>()?;
        let unknown2 = reader.read_u32::<LittleEndian>()?;
        let unknown3 = reader.read_u32::<LittleEndian>()?;

        Ok(
            LnkHeader {
                _offset: _offset,
                header_size: header_size,
                guid: guid,
                data_flags: data_flags,
                file_flags: file_flags,
                created: created,
                accessed: accessed,
                modified: modified,
                file_size: file_size,
                icon_offset: icon_offset,
                window_flag: window_flag,
                hot_key: hot_key,
                unknown1: unknown1,
                unknown2: unknown2,
                unknown3: unknown3
            }
        )
    }

    pub fn get_data_flags(&self) -> DataFlags {
        self.data_flags
    }
}

#[derive(Serialize,Debug)]
pub struct TargetIdList {
    #[serde(skip_serializing)]
    _offset: u64,
    pub list_size: u16,
    pub shell_items: ShellList
}

impl TargetIdList{
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<TargetIdList, LnkError> {
        let _offset = reader.seek(SeekFrom::Current(0))?;
        let list_size = reader.read_u16::<LittleEndian>()?;

        let shell_items = ShellList::new(
            &mut reader
        )?;

        Ok(
            TargetIdList {
                _offset: _offset,
                list_size: list_size,
                shell_items: shell_items
            }
        )
    }

    pub fn get_size(&self) -> u16 {
        self.list_size
    }
}

#[derive(Serialize,Debug)]
pub struct DataStrings {
    pub description: Option<String>,
    pub relative_path: Option<String>,
    pub working_directory: Option<String>,
    pub command_line_args: Option<String>,
    pub icon_location: Option<String>
}
impl DataStrings {
    pub fn new<R: Read>(mut reader: R, data_flags: DataFlags) -> Result<DataStrings,LnkError> {
        let unicode_flag = data_flags.contains(flags::IS_UNICODE);

        let mut description = None;
        if data_flags.contains(flags::HAS_NAME) {
            if unicode_flag {
                description = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                description = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut relative_path = None;
        if data_flags.contains(flags::HAS_RELATIVE_PATH) {
            if unicode_flag {
                relative_path = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                relative_path = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut working_directory = None;
        if data_flags.contains(flags::HAS_WORKING_DIR) {
            if unicode_flag {
                working_directory = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                working_directory = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut command_line_args = None;
        if data_flags.contains(flags::HAS_ARGUMENTS) {
            if unicode_flag {
                command_line_args = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                command_line_args = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        let mut icon_location = None;
        if data_flags.contains(flags::HAS_ICON_LOCATION) {
            if unicode_flag {
                icon_location = Some(utils::read_string_u16_w_size(&mut reader)?);
            } else {
                icon_location = Some(utils::read_string_u8_w_size(&mut reader)?);
            }
        }

        Ok(
            DataStrings {
                description: description,
                relative_path: relative_path,
                working_directory: working_directory,
                command_line_args: command_line_args,
                icon_location: icon_location
            }
        )
    }
}

#[derive(Serialize,Debug)]
pub struct Lnk {
    pub header: LnkHeader,
    pub target_list: Option<TargetIdList>,
    pub location_info: Option<LocationInfo>,
    pub data_strings: DataStrings,
    pub extra_data: ExtraDataBlocks
}

impl Lnk {
    pub fn new<Rs: Read+Seek>(mut reader: Rs) -> Result<Lnk,LnkError> {
        // Check reader size
        let reader_size = utils::get_reader_size(
            &mut reader
        )?;
        if reader_size < 76 {
            return Err(
                LnkError::validation_error(
                    format!("File size of {} is less than 76.",reader_size)
                )
            );
        }

        let header = LnkHeader::new(
            &mut reader
        )?;
        let header_flags = header.get_data_flags();

        let mut target_list = None;
        if header_flags.contains(flags::HAS_TARGET_ID_LIST) {
            target_list = Some(
                TargetIdList::new(&mut reader)?
            );
        }

        let mut location_info = None;
        if header_flags.contains(flags::HAS_LINK_INFO) {
            location_info = Some(
                LocationInfo::new(&mut reader)?
            );
        }

        let data_strings = DataStrings::new(
            &mut reader,
            header_flags
        )?;

        let extra_data = ExtraDataBlocks::new(
            &mut reader
        )?;

        Ok(
            Lnk {
                header: header,
                target_list: target_list,
                location_info: location_info,
                data_strings: data_strings,
                extra_data: extra_data
            }
        )
    }
}
<|endoftext|>