<commit_before>use {AsByte, FromSingleByte, IntoBytes};
use frame::*;
use frame::frame_query::QueryFlags;
use types::*;
use types::value::Value;
use consistency::Consistency;

/// BodyResReady
#[derive(Clone)]
pub struct BodyReqBatch {
    pub batch_type: BatchType,
    pub queries: Vec<BatchQuery>,
    pub consistency: Consistency,
    /// **IMPORTANT NOTE:** this feature does not work and should not be used.
    /// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L409
    pub query_flags: Vec<QueryFlags>,
    pub serial_consistency: Option<Consistency>,
    pub timestamp: Option<i64>
}

impl IntoBytes for BodyReqBatch {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut bytes = vec![];

        bytes.push(self.batch_type.as_byte());

        bytes.extend_from_slice(to_short(self.queries.len() as u64).as_slice());

        bytes = self.queries
            .iter()
            .fold(bytes, |mut _bytes, q| {
                _bytes.extend_from_slice(q.into_cbytes().as_slice());
                _bytes
            });

        bytes.extend_from_slice(self.consistency.into_cbytes().as_slice());

        let flag_byte = self.query_flags
            .iter()
            .fold(0, |mut _bytes, f|  _bytes | f.as_byte());
        bytes.push(flag_byte);

        if let Some(ref serial_consistency) = self.serial_consistency {
            bytes.extend_from_slice(serial_consistency.into_cbytes().as_slice());
        }

        if let Some(ref timestamp) = self.timestamp {
            bytes.extend_from_slice(to_int(timestamp.clone()).as_slice());
        }

        bytes
    }
}

/// Batch type
#[derive(Debug, Clone)]
pub enum BatchType {
    /// The batch will be "logged". This is equivalent to a
    /// normal CQL3 batch statement.
    Logged,
    /// The batch will be "unlogged".
    Unlogged,
    /// The batch will be a "counter" batch (and non-counter
    /// statements will be rejected).
    Counter
}

impl FromSingleByte for BatchType {
    fn from_byte(byte: u8) -> BatchType {
        match byte {
            0 => BatchType::Logged,
            1 => BatchType::Unlogged,
            2 => BatchType::Counter,
            _ => unreachable!()
        }
    }
}

impl AsByte for BatchType {
    fn as_byte(&self) -> u8 {
        return match self {
            &BatchType::Logged => 0,
            &BatchType::Unlogged => 1,
            &BatchType::Counter => 2
        }
    }
}

/// The structure that represents a query to be batched.
#[derive(Clone)]
pub struct BatchQuery {
    /// It indicates if a query was prepared.
    pub is_prepared: bool,
    /// It contains either id of prepared query of a query itself.
    pub subject: BatchQuerySubj,
    /// It is the optional name of the following <value_i>. It must be present
    /// if and only if the 0x40 flag is provided for the batch.
    /// **Important note:** this feature does not work and should not be
    /// used. It is specified in a way that makes it impossible for the server
    /// to implement. This will be fixed in a future version of the native
    /// protocol. See https://issues.apache.org/jira/browse/CASSANDRA-10246 for
    /// more details
    pub values: Vec<(Option<CString>, Value)>
}

/// It contains either an id of prepared query or CQL string.
#[derive(Clone)]
pub enum BatchQuerySubj {
    PreparedId(CBytesShort),
    QueryString(CStringLong)
}

impl IntoBytes for BatchQuery {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut bytes = vec![];

        // kind
        if self.is_prepared {
            bytes.push(1);
        } else {
            bytes.push(0);
        }

        match self.subject {
            BatchQuerySubj::PreparedId(ref s) => {
                bytes.extend_from_slice(s.into_cbytes().as_slice());
            },
            BatchQuerySubj::QueryString(ref s) => {
                bytes.extend_from_slice(s.into_cbytes().as_slice());
            }
        }

        bytes.extend_from_slice(to_short(self.values.len() as u64).as_slice());

        bytes = self.values
            .iter()
            .fold(bytes, |mut _bytes, v| {
                if let Some(ref name) = v.0 {
                    _bytes.extend_from_slice(name.into_cbytes().as_slice());
                }

                _bytes.extend_from_slice(v.1.into_cbytes().as_slice());

                _bytes
            });

        bytes
    }
}

impl Frame {
    /// **Note:** This function should be used internally for building query request frames.
    pub fn new_req_batch(
        query: BodyReqBatch,
        flags: Vec<Flag>
    ) -> Frame {
        let version = Version::Request;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::Batch;

        return Frame {
            version: version,
            flags: flags,
            stream: stream,
            opcode: opcode,
            body: query.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![]
        };
    }
}
<commit_msg>Fix a comment<commit_after>use {AsByte, FromSingleByte, IntoBytes};
use frame::*;
use frame::frame_query::QueryFlags;
use types::*;
use types::value::Value;
use consistency::Consistency;

/// BodyResReady
#[derive(Clone)]
pub struct BodyReqBatch {
    pub batch_type: BatchType,
    pub queries: Vec<BatchQuery>,
    pub consistency: Consistency,
    /// **IMPORTANT NOTE:** with names flag does not work and should not be used.
    /// https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L409
    pub query_flags: Vec<QueryFlags>,
    pub serial_consistency: Option<Consistency>,
    pub timestamp: Option<i64>
}

impl IntoBytes for BodyReqBatch {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut bytes = vec![];

        bytes.push(self.batch_type.as_byte());

        bytes.extend_from_slice(to_short(self.queries.len() as u64).as_slice());

        bytes = self.queries
            .iter()
            .fold(bytes, |mut _bytes, q| {
                _bytes.extend_from_slice(q.into_cbytes().as_slice());
                _bytes
            });

        bytes.extend_from_slice(self.consistency.into_cbytes().as_slice());

        let flag_byte = self.query_flags
            .iter()
            .fold(0, |mut _bytes, f|  _bytes | f.as_byte());
        bytes.push(flag_byte);

        if let Some(ref serial_consistency) = self.serial_consistency {
            bytes.extend_from_slice(serial_consistency.into_cbytes().as_slice());
        }

        if let Some(ref timestamp) = self.timestamp {
            bytes.extend_from_slice(to_int(timestamp.clone()).as_slice());
        }

        bytes
    }
}

/// Batch type
#[derive(Debug, Clone)]
pub enum BatchType {
    /// The batch will be "logged". This is equivalent to a
    /// normal CQL3 batch statement.
    Logged,
    /// The batch will be "unlogged".
    Unlogged,
    /// The batch will be a "counter" batch (and non-counter
    /// statements will be rejected).
    Counter
}

impl FromSingleByte for BatchType {
    fn from_byte(byte: u8) -> BatchType {
        match byte {
            0 => BatchType::Logged,
            1 => BatchType::Unlogged,
            2 => BatchType::Counter,
            _ => unreachable!()
        }
    }
}

impl AsByte for BatchType {
    fn as_byte(&self) -> u8 {
        return match self {
            &BatchType::Logged => 0,
            &BatchType::Unlogged => 1,
            &BatchType::Counter => 2
        }
    }
}

/// The structure that represents a query to be batched.
#[derive(Clone)]
pub struct BatchQuery {
    /// It indicates if a query was prepared.
    pub is_prepared: bool,
    /// It contains either id of prepared query of a query itself.
    pub subject: BatchQuerySubj,
    /// It is the optional name of the following <value_i>. It must be present
    /// if and only if the 0x40 flag is provided for the batch.
    /// **Important note:** this feature does not work and should not be
    /// used. It is specified in a way that makes it impossible for the server
    /// to implement. This will be fixed in a future version of the native
    /// protocol. See https://issues.apache.org/jira/browse/CASSANDRA-10246 for
    /// more details
    pub values: Vec<(Option<CString>, Value)>
}

/// It contains either an id of prepared query or CQL string.
#[derive(Clone)]
pub enum BatchQuerySubj {
    PreparedId(CBytesShort),
    QueryString(CStringLong)
}

impl IntoBytes for BatchQuery {
    fn into_cbytes(&self) -> Vec<u8> {
        let mut bytes = vec![];

        // kind
        if self.is_prepared {
            bytes.push(1);
        } else {
            bytes.push(0);
        }

        match self.subject {
            BatchQuerySubj::PreparedId(ref s) => {
                bytes.extend_from_slice(s.into_cbytes().as_slice());
            },
            BatchQuerySubj::QueryString(ref s) => {
                bytes.extend_from_slice(s.into_cbytes().as_slice());
            }
        }

        bytes.extend_from_slice(to_short(self.values.len() as u64).as_slice());

        bytes = self.values
            .iter()
            .fold(bytes, |mut _bytes, v| {
                if let Some(ref name) = v.0 {
                    _bytes.extend_from_slice(name.into_cbytes().as_slice());
                }

                _bytes.extend_from_slice(v.1.into_cbytes().as_slice());

                _bytes
            });

        bytes
    }
}

impl Frame {
    /// **Note:** This function should be used internally for building query request frames.
    pub fn new_req_batch(
        query: BodyReqBatch,
        flags: Vec<Flag>
    ) -> Frame {
        let version = Version::Request;
        // sync client
        let stream: u64 = 0;
        let opcode = Opcode::Batch;

        return Frame {
            version: version,
            flags: flags,
            stream: stream,
            opcode: opcode,
            body: query.into_cbytes(),
            // for request frames it's always None
            tracing_id: None,
            warnings: vec![]
        };
    }
}
<|endoftext|>


<commit_before>//!Types for interpolation between multiple colors.

use std::cmp::max;

use Mix;

///A linear interpolation between colors.
///
///It's used to smoothly transition between a series of colors, that can be
///either evenly spaced or have customized positions. The gradient is
///continuous between the control points, but it's possible to iterate over a
///number of evenly spaced points using the `take` method. Any point outside
///the domain of the gradient will have the same color as the closest control
///point.
#[derive(Clone)]
pub struct Gradient<C: Mix + Clone>(Vec<(f32, C)>);

impl<C: Mix + Clone> Gradient<C> {
    ///Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
    ///There must be at least one color.
    pub fn new<I: IntoIterator<Item=C>>(colors: I) -> Gradient<C> {
        let mut points: Vec<_> = colors.into_iter().map(|c| (0.0, c)).collect();
        assert!(points.len() > 0);
        let step_size = 1.0 / max(points.len() - 1, 1) as f32;

        for (i, &mut (ref mut p, _)) in points.iter_mut().enumerate() {
            *p = i as f32 * step_size;
        }

        Gradient(points)
    }

    ///Create a gradient of colors with custom spacing and domain. There must be
    ///at least one color and they are expected to be ordered by their
    ///position value.
    pub fn with_domain(colors: Vec<(f32, C)>) -> Gradient<C> {
        assert!(colors.len() > 0);

        //Maybe sort the colors?
        Gradient(colors)
    }

    ///Get a color from the gradient. The color of the closest control point
    ///will be returned if `i` is outside the domain.
    pub fn get(&self, i: f32) -> C {
        let &(mut min, ref min_color) = self.0.get(0).expect("a Gradient must contain at least one color");
        let mut min_color = min_color;
        let mut min_index = 0;

        if i <= min {
            return min_color.clone();
        }

        let &(mut max, ref max_color) = self.0.last().expect("a Gradient must contain at least one color");
        let mut max_color = max_color;
        let mut max_index = self.0.len() - 1;

        if i >= max {
            return max_color.clone();
        }

        while min_index < max_index - 1 {
            let index = min_index + (max_index - min_index) / 2;

            let (p, ref color) = self.0[index];

            if i <= p {
                max = p;
                max_color = color;
                max_index = index;
            } else {
                min = p;
                min_color = color;
                min_index = index;
            }
        }

        let factor = (i - min) / (max - min);

        min_color.mix(max_color, factor)
    }

    ///Take `n` evenly spaced colors from the gradient, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let &(min, _) = self.0.get(0).expect("a Gradient must contain at least one color");
        let &(max, _) = self.0.last().expect("a Gradient must contain at least one color");

        Take {
            gradient: self,
            from: min,
            diff: max - min,
            len: n,
            current: 0,
        }
    }
}

///An iterator over interpolated colors.
pub struct Take<'a, C: Mix + Clone + 'a> {
    gradient: &'a Gradient<C>,
    from: f32,
    diff: f32,
    len: usize,
    current: usize,
}

impl<'a, C: Mix + Clone> Iterator for Take<'a, C> {
    type Item = C;

    fn next(&mut self) -> Option<C> {
        if self.current < self.len {
            let i = self.from + self.current as f32 * (self.diff / self.len as f32);
            self.current += 1;
            Some(self.gradient.get(i))
        } else {
            None
        }
    }
}
<commit_msg>Define size_hint and implement ExactSizeIterator for Take<commit_after>//!Types for interpolation between multiple colors.

use std::cmp::max;

use Mix;

///A linear interpolation between colors.
///
///It's used to smoothly transition between a series of colors, that can be
///either evenly spaced or have customized positions. The gradient is
///continuous between the control points, but it's possible to iterate over a
///number of evenly spaced points using the `take` method. Any point outside
///the domain of the gradient will have the same color as the closest control
///point.
#[derive(Clone)]
pub struct Gradient<C: Mix + Clone>(Vec<(f32, C)>);

impl<C: Mix + Clone> Gradient<C> {
    ///Create a gradient of evenly spaced colors with the domain [0.0, 1.0].
    ///There must be at least one color.
    pub fn new<I: IntoIterator<Item=C>>(colors: I) -> Gradient<C> {
        let mut points: Vec<_> = colors.into_iter().map(|c| (0.0, c)).collect();
        assert!(points.len() > 0);
        let step_size = 1.0 / max(points.len() - 1, 1) as f32;

        for (i, &mut (ref mut p, _)) in points.iter_mut().enumerate() {
            *p = i as f32 * step_size;
        }

        Gradient(points)
    }

    ///Create a gradient of colors with custom spacing and domain. There must be
    ///at least one color and they are expected to be ordered by their
    ///position value.
    pub fn with_domain(colors: Vec<(f32, C)>) -> Gradient<C> {
        assert!(colors.len() > 0);

        //Maybe sort the colors?
        Gradient(colors)
    }

    ///Get a color from the gradient. The color of the closest control point
    ///will be returned if `i` is outside the domain.
    pub fn get(&self, i: f32) -> C {
        let &(mut min, ref min_color) = self.0.get(0).expect("a Gradient must contain at least one color");
        let mut min_color = min_color;
        let mut min_index = 0;

        if i <= min {
            return min_color.clone();
        }

        let &(mut max, ref max_color) = self.0.last().expect("a Gradient must contain at least one color");
        let mut max_color = max_color;
        let mut max_index = self.0.len() - 1;

        if i >= max {
            return max_color.clone();
        }

        while min_index < max_index - 1 {
            let index = min_index + (max_index - min_index) / 2;

            let (p, ref color) = self.0[index];

            if i <= p {
                max = p;
                max_color = color;
                max_index = index;
            } else {
                min = p;
                min_color = color;
                min_index = index;
            }
        }

        let factor = (i - min) / (max - min);

        min_color.mix(max_color, factor)
    }

    ///Take `n` evenly spaced colors from the gradient, as an iterator.
    pub fn take(&self, n: usize) -> Take<C> {
        let &(min, _) = self.0.get(0).expect("a Gradient must contain at least one color");
        let &(max, _) = self.0.last().expect("a Gradient must contain at least one color");

        Take {
            gradient: self,
            from: min,
            diff: max - min,
            len: n,
            current: 0,
        }
    }
}

///An iterator over interpolated colors.
pub struct Take<'a, C: Mix + Clone + 'a> {
    gradient: &'a Gradient<C>,
    from: f32,
    diff: f32,
    len: usize,
    current: usize,
}

impl<'a, C: Mix + Clone> Iterator for Take<'a, C> {
    type Item = C;

    fn next(&mut self) -> Option<C> {
        if self.current < self.len {
            let i = self.from + self.current as f32 * (self.diff / self.len as f32);
            self.current += 1;
            Some(self.gradient.get(i))
        } else {
            None
        }
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        (self.len - self.current, Some(self.len - self.current))
    }
}

impl<'a, C: Mix + Clone> ExactSizeIterator for Take<'a, C> { }
<|endoftext|>


<commit_before>use app::App;
// Third Party
#[cfg(feature = "suggestions")]
use strsim;

// Internal
use fmt::Format;

/// Produces a string from a given list of possible values which is similar to
/// the passed in value `v` with a certain confidence.
/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
/// `Some("foo")`, whereas "blark" would yield `None`.
#[cfg(feature = "suggestions")]
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str>
where
    T: AsRef<str> + 'a,
    I: IntoIterator<Item = &'a T>,
{
    let mut candidate: Option<(f64, &str)> = None;
    for pv in possible_values {
        let confidence = strsim::jaro_winkler(v, pv.as_ref());
        if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
        {
            candidate = Some((confidence, pv.as_ref()));
        }
    }
    match candidate {
        None => None,
        Some((_, candidate)) => Some(candidate),
    }
}

#[cfg(not(feature = "suggestions"))]
pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str>
where
    T: AsRef<str> + 'a,
    I: IntoIterator<Item = &'a T>,
{
    None
}

/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean_flag_suffix<'z, T, I>(
    arg: &str,
    args_rest: &'z [&str],
    longs: I,
    subcommands: &'z [App],
) -> (String, Option<&'z str>)
where
    T: AsRef<str> + 'z,
    I: IntoIterator<Item = &'z T>,
{
    if let Some(candidate) = did_you_mean(arg, longs) {
        let suffix = format!(
            "\n\tDid you mean {}{}?",
            Format::Good("--"),
            Format::Good(candidate)
            );
        return (suffix, Some(candidate));
    }

    subcommands
        .into_iter()
        .filter_map(|subcommand| {
            let opts = subcommand
                .p
                .flags
                .iter()
                .filter_map(|f| f.s.long)
                .chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));

            let candidate = did_you_mean(arg, opts)?;
            let score = args_rest.iter().position(|x| *x == subcommand.get_name())?;

            let suffix = format!(
                "\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
                Format::Good("--"),
                Format::Good(candidate),
                Format::Good(subcommand.get_name())
            );

            Some((score, (suffix, Some(candidate))))
        })
        .min_by_key(|&(score, _)| score)
        .map(|(_, suggestion)| suggestion)
        .unwrap_or_else(|| (String::new(), None))
}

/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>)
where
    T: AsRef<str> + 'z,
    I: IntoIterator<Item = &'z T>,
{
    match did_you_mean(arg, values) {
        Some(candidate) => {
            let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate));
            (suffix, Some(candidate))
        }
        None => (String::new(), None),
    }
}

#[cfg(all(test, features = "suggestions"))]
mod test {
    use super::*;

    #[test]
    fn possible_values_match() {
        let p_vals = ["test", "possible", "values"];
        assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test"));
    }

    #[test]
    fn possible_values_nomatch() {
        let p_vals = ["test", "possible", "values"];
        assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none());
    }

    #[test]
    fn suffix_long() {
        let p_vals = ["test", "possible", "values"];
        let suffix = "\n\tDid you mean \'--test\'?";
        assert_eq!(
            did_you_mean_flag_suffix("tst", p_vals.iter(), []),
            (suffix, Some("test"))
        );
    }

    #[test]
    fn suffix_enum() {
        let p_vals = ["test", "possible", "values"];
        let suffix = "\n\tDid you mean \'test\'?";
        assert_eq!(
            did_you_mean_value_suffix("tst", p_vals.iter()),
            (suffix, Some("test"))
        );
    }
}
<commit_msg>fix: Restore compat with Rust 1.21<commit_after>use app::App;
// Third Party
#[cfg(feature = "suggestions")]
use strsim;

// Internal
use fmt::Format;

/// Produces a string from a given list of possible values which is similar to
/// the passed in value `v` with a certain confidence.
/// Thus in a list of possible values like ["foo", "bar"], the value "fop" will yield
/// `Some("foo")`, whereas "blark" would yield `None`.
#[cfg(feature = "suggestions")]
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean<'a, T: ?Sized, I>(v: &str, possible_values: I) -> Option<&'a str>
where
    T: AsRef<str> + 'a,
    I: IntoIterator<Item = &'a T>,
{
    let mut candidate: Option<(f64, &str)> = None;
    for pv in possible_values {
        let confidence = strsim::jaro_winkler(v, pv.as_ref());
        if confidence > 0.8 && (candidate.is_none() || (candidate.as_ref().unwrap().0 < confidence))
        {
            candidate = Some((confidence, pv.as_ref()));
        }
    }
    match candidate {
        None => None,
        Some((_, candidate)) => Some(candidate),
    }
}

#[cfg(not(feature = "suggestions"))]
pub fn did_you_mean<'a, T: ?Sized, I>(_: &str, _: I) -> Option<&'a str>
where
    T: AsRef<str> + 'a,
    I: IntoIterator<Item = &'a T>,
{
    None
}

/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
#[cfg_attr(feature = "lints", allow(needless_lifetimes))]
pub fn did_you_mean_flag_suffix<'z, T, I>(
    arg: &str,
    args_rest: &'z [&str],
    longs: I,
    subcommands: &'z [App],
) -> (String, Option<&'z str>)
where
    T: AsRef<str> + 'z,
    I: IntoIterator<Item = &'z T>,
{
    if let Some(candidate) = did_you_mean(arg, longs) {
        let suffix = format!(
            "\n\tDid you mean {}{}?",
            Format::Good("--"),
            Format::Good(candidate)
            );
        return (suffix, Some(candidate));
    }

    subcommands
        .into_iter()
        .filter_map(|subcommand| {
            let opts = subcommand
                .p
                .flags
                .iter()
                .filter_map(|f| f.s.long)
                .chain(subcommand.p.opts.iter().filter_map(|o| o.s.long));

            let candidate = match did_you_mean(arg, opts) {
                Some(candidate) => candidate,
                None => return None
            };
            let score = match args_rest.iter().position(|x| *x == subcommand.get_name()) {
                Some(score) => score,
                None => return None
            };

            let suffix = format!(
                "\n\tDid you mean to put '{}{}' after the subcommand '{}'?",
                Format::Good("--"),
                Format::Good(candidate),
                Format::Good(subcommand.get_name())
            );

            Some((score, (suffix, Some(candidate))))
        })
        .min_by_key(|&(score, _)| score)
        .map(|(_, suggestion)| suggestion)
        .unwrap_or_else(|| (String::new(), None))
}

/// Returns a suffix that can be empty, or is the standard 'did you mean' phrase
pub fn did_you_mean_value_suffix<'z, T, I>(arg: &str, values: I) -> (String, Option<&'z str>)
where
    T: AsRef<str> + 'z,
    I: IntoIterator<Item = &'z T>,
{
    match did_you_mean(arg, values) {
        Some(candidate) => {
            let suffix = format!("\n\tDid you mean '{}'?", Format::Good(candidate));
            (suffix, Some(candidate))
        }
        None => (String::new(), None),
    }
}

#[cfg(all(test, features = "suggestions"))]
mod test {
    use super::*;

    #[test]
    fn possible_values_match() {
        let p_vals = ["test", "possible", "values"];
        assert_eq!(did_you_mean("tst", p_vals.iter()), Some("test"));
    }

    #[test]
    fn possible_values_nomatch() {
        let p_vals = ["test", "possible", "values"];
        assert!(did_you_mean("hahaahahah", p_vals.iter()).is_none());
    }

    #[test]
    fn suffix_long() {
        let p_vals = ["test", "possible", "values"];
        let suffix = "\n\tDid you mean \'--test\'?";
        assert_eq!(
            did_you_mean_flag_suffix("tst", p_vals.iter(), []),
            (suffix, Some("test"))
        );
    }

    #[test]
    fn suffix_enum() {
        let p_vals = ["test", "possible", "values"];
        let suffix = "\n\tDid you mean \'test\'?";
        assert_eq!(
            did_you_mean_value_suffix("tst", p_vals.iter()),
            (suffix, Some("test"))
        );
    }
}
<|endoftext|>


<commit_before>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;

pub mod frame;
pub mod transport;
pub mod connection;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    UnableToConnect,
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;
<commit_msg>Derive some traits for HttpError<commit_after>//! The module implements the client side of the HTTP/2 protocol and exposes
//! an API for using it.
use std::io;

pub mod frame;
pub mod transport;
pub mod connection;

/// An alias for the type that represents the ID of an HTTP/2 stream
pub type StreamId = u32;
/// An alias for the type that represents HTTP/2 haders. For now we only alias
/// the tuple of byte vectors instead of going with a full struct representation.
pub type Header = (Vec<u8>, Vec<u8>);

/// An enum representing errors that can arise when performing operations
/// involving an HTTP/2 connection.
#[derive(PartialEq)]
#[derive(Clone)]
#[derive(Debug)]
pub enum HttpError {
    IoError(io::Error),
    UnknownFrameType,
    InvalidFrame,
    UnableToConnect,
}

/// A convenience `Result` type that has the `HttpError` type as the error
/// type and a generic Ok result type.
pub type HttpResult<T> = Result<T, HttpError>;
<|endoftext|>


<commit_before>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// util.rs
//   various utility functions for doings things we need to do.

use std::old_io::stdio::{stdin};
use std::old_io::{File, Open, ReadWrite,
              TempDir, Command, SeekSet};
use time::{get_time};
use std::os::{getenv, homedir};
use std::old_io::process::{InheritFd};
use term::{stdout};
use term::attr::Attr::{Bold};
use std::old_io::{IoError};
use std::os::errno;
use std::cmp::{Ordering};
use time::{strftime, strptime, at, Tm};
use std::iter::{repeat};
use rustc_serialize::json::{as_pretty_json};

use ::{DATEFMT, DATEFMT_SHORT, ThecaItem};
use errors::{ThecaError, GenericError};
use lineformat::{LineFormat};

pub use libc::{
    STDIN_FILENO,
    STDOUT_FILENO,
    STDERR_FILENO
};

// c calls for TIOCGWINSZ
pub mod c {
    extern crate libc;
    pub use self::libc::{
        c_int,
        c_uint,
        c_ushort,
        c_ulong,
        c_uchar,
        STDOUT_FILENO,
        isatty
    };
    use std::mem::zeroed;
    #[derive(Copy)]
    pub struct Winsize {
        pub ws_row: c_ushort,
        pub ws_col: c_ushort
    }
    #[repr(C)]
    #[derive(Copy)]
    pub struct Termios {
        pub c_iflag: c_uint,
        pub c_oflag: c_uint,
        pub c_cflag: c_uint,
        pub c_lflag: c_uint,
        pub c_line: c_uchar,
        pub c_cc: [c_uchar; 32us],
        pub c_ispeed: c_uint,
        pub c_ospeed: c_uint,
    }
    impl Termios {
        pub fn new() -> Termios {
            unsafe {zeroed()}
        }
    }
    pub fn tcgetattr(fd: c_int, termios_p: &mut Termios) -> c_int {
        extern {fn tcgetattr(fd: c_int, termios_p: *mut Termios) -> c_int;}
        unsafe {tcgetattr(fd, termios_p as *mut _)}
    }
    pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios_p: &Termios) -> c_int {
        extern {fn tcsetattr(fd: c_int, optional_actions: c_int,
                              termios_p: *const Termios) -> c_int;}
        unsafe {tcsetattr(fd, optional_actions, termios_p as *const _)}
    }
    pub const ECHO:c_uint = 8;
    pub const TCSANOW: c_int = 0;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    static TIOCGWINSZ: c_ulong = 0x5413;
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    static TIOCGWINSZ: c_ulong = 0x40087468;
    extern {
        pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
    }
    pub unsafe fn dimensions() -> Winsize {
        let mut window: Winsize = zeroed();
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window as *mut Winsize);
        window
    }
    pub fn istty(fd: c_int) -> bool {
        let isit = unsafe {isatty(fd as i32)};
        isit != 0
    }
}

fn set_term_echo(echo: bool) -> Result<(), ThecaError> {
    let mut t = c::Termios::new();
    try_errno!(c::tcgetattr(STDIN_FILENO, &mut t));
    match echo {
        true => t.c_lflag |= c::ECHO,  // on
        false => t.c_lflag &= !c::ECHO  // off
    };
    try_errno!(c::tcsetattr(STDIN_FILENO, c::TCSANOW, &mut t));
    Ok(())
}

// unsafety wrapper
pub fn termsize() -> usize {
    let ws = unsafe {c::dimensions()};
    if ws.ws_col <= 0 || ws.ws_row <= 0 {
        0
    }
    else {
        ws.ws_col as usize
    }
}

pub fn drop_to_editor(contents: &String) -> Result<String, ThecaError> {
    // setup temporary directory
    let tmpdir = try!(TempDir::new("theca"));
    // setup temporary file to write/read
    let tmppath = tmpdir.path().join(get_time().sec.to_string());
    let mut tmpfile = try!(File::open_mode(&tmppath, Open, ReadWrite));
    try!(tmpfile.write_line(&contents[]));
    // we now have a temp file, at `tmppath`, that contains `contents`
    // first we need to know which onqe
    let editor = match getenv("VISUAL") {
        Some(val) => val,
        None => {
            match getenv("EDITOR") {
                Some(val) => val,
                None => specific_fail!("neither $VISUAL nor $EDITOR is set.".to_string())
            }
        }
    };
    // lets start `editor` and edit the file at `tmppath`
    // first we need to set STDIN, STDOUT, and STDERR to those that theca is
    // currently using so we can display the editor
    let mut editor_command = Command::new(editor);
    editor_command.arg(tmppath.display().to_string());
    editor_command.stdin(InheritFd(STDIN_FILENO));
    editor_command.stdout(InheritFd(STDOUT_FILENO));
    editor_command.stderr(InheritFd(STDERR_FILENO));
    let editor_proc = editor_command.spawn();
    match try!(editor_proc).wait().is_ok() {
        true => {
            // finished editing, time to read `tmpfile` for the final output
            // seek to start of `tmpfile`
            try!(tmpfile.seek(0, SeekSet));
            Ok(try!(tmpfile.read_to_string()).trim().to_string())
        }
        false => specific_fail!("the editor broke... I think".to_string())
    }
}

pub fn get_password() -> Result<String, ThecaError> {
    // should really turn off terminal echo...
    print!("Key: ");
    let tty = c::istty(STDIN_FILENO);
    if tty {try!(set_term_echo(false));}
    let mut stdin = stdin();
    // since this only reads one line of stdin it could still feasibly
    // be used with `-` to set note body?
    let key = try!(stdin.read_line());
    if tty {try!(set_term_echo(true));}
    println!("");
    Ok(key.trim().to_string())
}

pub fn get_yn_input() -> Result<bool, ThecaError> {
    let mut stdin = stdin();
    let mut answer;
    let yes = vec!["y", "Y", "yes", "YES", "Yes"];
    let no = vec!["n", "N", "no", "NO", "No"];
    loop {
        print!("[y/n]# ");
        let mut input = try!(stdin.read_line());
        input = input.trim().to_string();
        match yes.iter().any(|n| &n[] == input) {
            true => {
                answer = true;
                break;
            },
            false => {
                match no.iter().any(|n| &n[] == input) {
                    true => {
                        answer = false;
                        break;
                    },
                    false => ()
                }
            }
        };
        println!("invalid input.");
    }
    Ok(answer)
}

pub fn pretty_line(bold: &str, plain: &String, tty: bool) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail!("could not retrieve standard output.".to_string())
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(t, "{}", bold.to_string()));
    if tty {try!(t.reset());}
    try!(write!(t, "{}", plain));
    Ok(())
}

pub fn format_field(value: &String, width: usize, truncate: bool) -> String {
    if value.len() > width && width > 3 && truncate {
        format!("{: <1$.1$}...", value, width-3)
    } else {
        format!("{: <1$.1$}", value, width)
    }
}

fn print_header(line_format: &LineFormat) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail!("could not retrieve standard output.".to_string())
    };
    let column_seperator: String = repeat(' ').take(line_format.colsep).collect();
    let header_seperator: String = repeat('-').take(line_format.line_width()).collect();
    let tty = c::istty(STDOUT_FILENO);
    let status = match line_format.status_width == 0 {
        true => "".to_string(),
        false => format_field(
            &"status".to_string(),
            line_format.status_width,
            false
        )+&*column_seperator
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(
                t,
                "{1}{0}{2}{0}{3}{4}\n{5}\n",
                column_seperator,
                format_field(&"id".to_string(), line_format.id_width, false),
                format_field(&"title".to_string(), line_format.title_width, false),
                status,
                format_field(&"last touched".to_string(), line_format.touched_width, false),
                header_seperator
            ));
    if tty {try!(t.reset());}
    Ok(())
}

pub fn sorted_print(
    notes: &mut Vec<ThecaItem>,
    limit: usize,
    condensed: bool,
    json: bool,
    datesort: bool,
    reverse: bool,
    search_body: bool
) -> Result<(), ThecaError> {
    let line_format = try!(LineFormat::new(notes, condensed, search_body));
    let limit = match limit != 0 && notes.len() >= limit {
        true => limit,
        false => notes.len()
    };
    if !condensed && !json {
        try!(print_header(&line_format));
    }
    // im not really sure why this... works?
    if datesort {
        notes.sort_by(|a, b| match cmp_last_touched(&*a.last_touched, &*b.last_touched) {
            Ok(o) => o,
            Err(_) => a.last_touched.cmp(&b.last_touched) // FIXME(?)
            // Err(_) => Ordering::Equal                  // FIXME(?)
        });
    }
    match json {
        false => {
            if reverse {notes.reverse();}
            for n in notes[0..limit].iter() {
                try!(n.print(&line_format, search_body));
            }
        },
        true => {
            if reverse { notes.reverse(); }
            println!("{}", as_pretty_json(notes))
        }
    };

    Ok(())
}

pub fn find_profile_folder(profile_folder: &String) -> Result<Path, ThecaError> {
    if !profile_folder.is_empty() {
        Ok(Path::new(profile_folder.to_string()))
    } else {
        match homedir() {
            Some(ref p) => Ok(p.join(".theca")),
            None => specific_fail!("failed to find your home directory".to_string())
        }
    }
}

pub fn parse_last_touched(lt: &str) -> Result<Tm, ThecaError> {
    Ok(at(try!(strptime(lt, DATEFMT)).to_timespec()))
}

pub fn localize_last_touched_string(lt: &str) -> Result<String, ThecaError> {
    let t = try!(parse_last_touched(lt));
    Ok(try!(strftime(DATEFMT_SHORT, &t)))
}

pub fn cmp_last_touched(a: &str, b: &str) -> Result<Ordering, ThecaError> {
    let a_tm = try!(parse_last_touched(a));
    let b_tm = try!(parse_last_touched(b));
    Ok(a_tm.cmp(&b_tm))
}
<commit_msg>json limit bug fix<commit_after>//  _   _
// | |_| |__   ___  ___ __ _
// | __| '_ \ / _ \/ __/ _` |
// | |_| | | |  __/ (_| (_| |
//  \__|_| |_|\___|\___\__,_|
//
// licensed under the MIT license <http://opensource.org/licenses/MIT>
//
// util.rs
//   various utility functions for doings things we need to do.

use std::old_io::stdio::{stdin};
use std::old_io::{File, Open, ReadWrite,
              TempDir, Command, SeekSet};
use time::{get_time};
use std::os::{getenv, homedir};
use std::old_io::process::{InheritFd};
use term::{stdout};
use term::attr::Attr::{Bold};
use std::old_io::{IoError};
use std::os::errno;
use std::cmp::{Ordering};
use time::{strftime, strptime, at, Tm};
use std::iter::{repeat};
use rustc_serialize::json::{as_pretty_json};

use ::{DATEFMT, DATEFMT_SHORT, ThecaItem};
use errors::{ThecaError, GenericError};
use lineformat::{LineFormat};

pub use libc::{
    STDIN_FILENO,
    STDOUT_FILENO,
    STDERR_FILENO
};

// c calls for TIOCGWINSZ
pub mod c {
    extern crate libc;
    pub use self::libc::{
        c_int,
        c_uint,
        c_ushort,
        c_ulong,
        c_uchar,
        STDOUT_FILENO,
        isatty
    };
    use std::mem::zeroed;
    #[derive(Copy)]
    pub struct Winsize {
        pub ws_row: c_ushort,
        pub ws_col: c_ushort
    }
    #[repr(C)]
    #[derive(Copy)]
    pub struct Termios {
        pub c_iflag: c_uint,
        pub c_oflag: c_uint,
        pub c_cflag: c_uint,
        pub c_lflag: c_uint,
        pub c_line: c_uchar,
        pub c_cc: [c_uchar; 32us],
        pub c_ispeed: c_uint,
        pub c_ospeed: c_uint,
    }
    impl Termios {
        pub fn new() -> Termios {
            unsafe {zeroed()}
        }
    }
    pub fn tcgetattr(fd: c_int, termios_p: &mut Termios) -> c_int {
        extern {fn tcgetattr(fd: c_int, termios_p: *mut Termios) -> c_int;}
        unsafe {tcgetattr(fd, termios_p as *mut _)}
    }
    pub fn tcsetattr(fd: c_int, optional_actions: c_int, termios_p: &Termios) -> c_int {
        extern {fn tcsetattr(fd: c_int, optional_actions: c_int,
                              termios_p: *const Termios) -> c_int;}
        unsafe {tcsetattr(fd, optional_actions, termios_p as *const _)}
    }
    pub const ECHO:c_uint = 8;
    pub const TCSANOW: c_int = 0;
    #[cfg(any(target_os = "linux", target_os = "android"))]
    static TIOCGWINSZ: c_ulong = 0x5413;
    #[cfg(any(target_os = "macos", target_os = "ios"))]
    static TIOCGWINSZ: c_ulong = 0x40087468;
    extern {
        pub fn ioctl(fd: c_int, request: c_ulong, ...) -> c_int;
    }
    pub unsafe fn dimensions() -> Winsize {
        let mut window: Winsize = zeroed();
        ioctl(STDOUT_FILENO, TIOCGWINSZ, &mut window as *mut Winsize);
        window
    }
    pub fn istty(fd: c_int) -> bool {
        let isit = unsafe {isatty(fd as i32)};
        isit != 0
    }
}

fn set_term_echo(echo: bool) -> Result<(), ThecaError> {
    let mut t = c::Termios::new();
    try_errno!(c::tcgetattr(STDIN_FILENO, &mut t));
    match echo {
        true => t.c_lflag |= c::ECHO,  // on
        false => t.c_lflag &= !c::ECHO  // off
    };
    try_errno!(c::tcsetattr(STDIN_FILENO, c::TCSANOW, &mut t));
    Ok(())
}

// unsafety wrapper
pub fn termsize() -> usize {
    let ws = unsafe {c::dimensions()};
    if ws.ws_col <= 0 || ws.ws_row <= 0 {
        0
    }
    else {
        ws.ws_col as usize
    }
}

pub fn drop_to_editor(contents: &String) -> Result<String, ThecaError> {
    // setup temporary directory
    let tmpdir = try!(TempDir::new("theca"));
    // setup temporary file to write/read
    let tmppath = tmpdir.path().join(get_time().sec.to_string());
    let mut tmpfile = try!(File::open_mode(&tmppath, Open, ReadWrite));
    try!(tmpfile.write_line(&contents[]));
    // we now have a temp file, at `tmppath`, that contains `contents`
    // first we need to know which onqe
    let editor = match getenv("VISUAL") {
        Some(val) => val,
        None => {
            match getenv("EDITOR") {
                Some(val) => val,
                None => specific_fail!("neither $VISUAL nor $EDITOR is set.".to_string())
            }
        }
    };
    // lets start `editor` and edit the file at `tmppath`
    // first we need to set STDIN, STDOUT, and STDERR to those that theca is
    // currently using so we can display the editor
    let mut editor_command = Command::new(editor);
    editor_command.arg(tmppath.display().to_string());
    editor_command.stdin(InheritFd(STDIN_FILENO));
    editor_command.stdout(InheritFd(STDOUT_FILENO));
    editor_command.stderr(InheritFd(STDERR_FILENO));
    let editor_proc = editor_command.spawn();
    match try!(editor_proc).wait().is_ok() {
        true => {
            // finished editing, time to read `tmpfile` for the final output
            // seek to start of `tmpfile`
            try!(tmpfile.seek(0, SeekSet));
            Ok(try!(tmpfile.read_to_string()).trim().to_string())
        }
        false => specific_fail!("the editor broke... I think".to_string())
    }
}

pub fn get_password() -> Result<String, ThecaError> {
    // should really turn off terminal echo...
    print!("Key: ");
    let tty = c::istty(STDIN_FILENO);
    if tty {try!(set_term_echo(false));}
    let mut stdin = stdin();
    // since this only reads one line of stdin it could still feasibly
    // be used with `-` to set note body?
    let key = try!(stdin.read_line());
    if tty {try!(set_term_echo(true));}
    println!("");
    Ok(key.trim().to_string())
}

pub fn get_yn_input() -> Result<bool, ThecaError> {
    let mut stdin = stdin();
    let mut answer;
    let yes = vec!["y", "Y", "yes", "YES", "Yes"];
    let no = vec!["n", "N", "no", "NO", "No"];
    loop {
        print!("[y/n]# ");
        let mut input = try!(stdin.read_line());
        input = input.trim().to_string();
        match yes.iter().any(|n| &n[] == input) {
            true => {
                answer = true;
                break;
            },
            false => {
                match no.iter().any(|n| &n[] == input) {
                    true => {
                        answer = false;
                        break;
                    },
                    false => ()
                }
            }
        };
        println!("invalid input.");
    }
    Ok(answer)
}

pub fn pretty_line(bold: &str, plain: &String, tty: bool) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail!("could not retrieve standard output.".to_string())
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(t, "{}", bold.to_string()));
    if tty {try!(t.reset());}
    try!(write!(t, "{}", plain));
    Ok(())
}

pub fn format_field(value: &String, width: usize, truncate: bool) -> String {
    if value.len() > width && width > 3 && truncate {
        format!("{: <1$.1$}...", value, width-3)
    } else {
        format!("{: <1$.1$}", value, width)
    }
}

fn print_header(line_format: &LineFormat) -> Result<(), ThecaError> {
    let mut t = match stdout() {
        Some(t) => t,
        None => specific_fail!("could not retrieve standard output.".to_string())
    };
    let column_seperator: String = repeat(' ').take(line_format.colsep).collect();
    let header_seperator: String = repeat('-').take(line_format.line_width()).collect();
    let tty = c::istty(STDOUT_FILENO);
    let status = match line_format.status_width == 0 {
        true => "".to_string(),
        false => format_field(
            &"status".to_string(),
            line_format.status_width,
            false
        )+&*column_seperator
    };
    if tty {try!(t.attr(Bold));}
    try!(write!(
                t,
                "{1}{0}{2}{0}{3}{4}\n{5}\n",
                column_seperator,
                format_field(&"id".to_string(), line_format.id_width, false),
                format_field(&"title".to_string(), line_format.title_width, false),
                status,
                format_field(&"last touched".to_string(), line_format.touched_width, false),
                header_seperator
            ));
    if tty {try!(t.reset());}
    Ok(())
}

pub fn sorted_print(
    notes: &mut Vec<ThecaItem>,
    limit: usize,
    condensed: bool,
    json: bool,
    datesort: bool,
    reverse: bool,
    search_body: bool
) -> Result<(), ThecaError> {
    let line_format = try!(LineFormat::new(notes, condensed, search_body));
    let limit = match limit != 0 && notes.len() >= limit {
        true => limit,
        false => notes.len()
    };
    if !condensed && !json {
        try!(print_header(&line_format));
    }
    if datesort {
        notes.sort_by(|a, b| match cmp_last_touched(&*a.last_touched, &*b.last_touched) {
            Ok(o) => o,
            Err(_) => a.last_touched.cmp(&b.last_touched) // FIXME(?)
            // Err(_) => Ordering::Equal                  // FIXME(?)
        });
    }
    match json {
        false => {
            if reverse {notes.reverse();}
            for n in notes[0..limit].iter() {
                try!(n.print(&line_format, search_body));
            }
        },
        true => {
            if reverse { notes.reverse(); }
            println!("{}", as_pretty_json(&notes[0..limit].to_vec()))
        }
    };

    Ok(())
}

pub fn find_profile_folder(profile_folder: &String) -> Result<Path, ThecaError> {
    if !profile_folder.is_empty() {
        Ok(Path::new(profile_folder.to_string()))
    } else {
        match homedir() {
            Some(ref p) => Ok(p.join(".theca")),
            None => specific_fail!("failed to find your home directory".to_string())
        }
    }
}

pub fn parse_last_touched(lt: &str) -> Result<Tm, ThecaError> {
    Ok(at(try!(strptime(lt, DATEFMT)).to_timespec()))
}

pub fn localize_last_touched_string(lt: &str) -> Result<String, ThecaError> {
    let t = try!(parse_last_touched(lt));
    Ok(try!(strftime(DATEFMT_SHORT, &t)))
}

pub fn cmp_last_touched(a: &str, b: &str) -> Result<Ordering, ThecaError> {
    let a_tm = try!(parse_last_touched(a));
    let b_tm = try!(parse_last_touched(b));
    Ok(a_tm.cmp(&b_tm))
}
<|endoftext|>


<commit_before>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<commit_msg>net/defs: Int now derives Ord, PartialOrd, Eq, PartialEq<commit_after>//! Various definitions of types, constants, traint, ... related to network

use core::fmt::{
    Binary,
    Octal,
    LowerHex,
    UpperHex,
    Debug,
    Display,
    Formatter,
    Error
};

use vec::Vec;
use string::String;

use num::PrimInt;

use net::Packet;

/// Trait implemented by hardware interfaces
pub trait Device {
    /// Periodically called by the network thread to let the interface
    /// refresh its rx/tx buffers, ...
    fn refresh(&mut self);

    /// Transmit a packet via the interface
    fn tx_packet(&mut self, pkt: Packet);
}

/// Network integer representation
///
/// This type stores an integer using network's endianness and let the user
/// manipulates it using host's endianness.
#[repr(C, packed)]
#[derive(Clone, Ord, PartialOrd, Eq, PartialEq)]
pub struct Int<T: PrimInt + Clone>(T);

impl<T> Int<T> where T: PrimInt + Clone {
    /// Construct from an integer represented using network's endianness
    pub fn from_net(i: T) -> Self {
        Int(i)
    }

    /// Construct from an integer represented using host's endianness
    pub fn from_host(i: T) -> Self {
        Int(i.to_be())
    }

    /// Returns the contained integer using host's endianness
    pub fn as_host(&self) -> T {
        T::from_be(self.0.clone())
    }

    /// Returns the contained integer using network's endianness
    pub fn as_net(&self) -> T {
        self.0.clone()
    }
}

impl<T> Binary for Int<T> where T: PrimInt + Clone + Binary {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Octal for Int<T> where T: PrimInt + Clone + Octal {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> LowerHex for Int<T> where T: PrimInt + Clone + LowerHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> UpperHex for Int<T> where T: PrimInt + Clone + UpperHex {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Debug for Int<T> where T: PrimInt + Clone + Debug {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

impl<T> Display for Int<T> where T: PrimInt + Clone + Display {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> { self.as_host().fmt(f) }
}

const COUNT_HWADDR_BYTES: usize = 6;

#[repr(C, packed)]
#[derive(Copy, Clone, PartialEq)]
/// An IPv4 address
pub struct Ipv4Addr {
    a: u8,
    b: u8,
    c: u8,
    d: u8,
}

impl Ipv4Addr {
    /// Creates a new IPv4 address
    ///
    /// The result will represent the IP address `a`.`b`.`c`.`d`
    pub fn new(a: u8, b: u8, c: u8, d: u8) -> Self {
        Ipv4Addr {
            a: a,
            b: b,
            c: c,
            d: d,
        }
    }
}

impl Display for Ipv4Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}.{}.{}.{}", self.a, self.b, self.c,
                                 self.d))
    }
}

#[repr(C, packed)]
#[derive(Clone, PartialEq)]
/// An IPv6 address
pub struct Ipv6Addr {
    a: Int<u16>,
    b: Int<u16>,
    c: Int<u16>,
    d: Int<u16>,
    e: Int<u16>,
    f: Int<u16>,
    g: Int<u16>,
    h: Int<u16>,
}

impl Ipv6Addr {
    /// Creates a new IPv6 address
    ///
    /// The result will represent the IP address `a`:`b`:`c`:`d`:`e`:`f`:`g`:`h`
    pub fn new(a: u16, b: u16, c: u16, d: u16, e: u16, f: u16, g: u16,
               h: u16) -> Ipv6Addr {
        Ipv6Addr {
            a: Int::from_host(a),
            b: Int::from_host(b),
            c: Int::from_host(c),
            d: Int::from_host(d),
            e: Int::from_host(e),
            f: Int::from_host(f),
            g: Int::from_host(g),
            h: Int::from_host(h),
        }
    }
}

impl Display for Ipv6Addr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{}:{}:{}:{}:{}:{}:{}:{}", self.a, self.b,
                                 self.c, self.d, self.e, self.f, self.g,
                                 self.h))
    }
}

#[repr(C, packed)]
#[derive(Copy, Clone)]
/// A MAC address
pub struct HwAddr {
    bytes: [u8; COUNT_HWADDR_BYTES],
}

impl HwAddr {
    /// Create an empty hardware address (i.e., 00:00:00:00:00:00)
    pub fn empty() -> Self {
        HwAddr {
            bytes: [0; COUNT_HWADDR_BYTES],
        }
    }

    /// Convert a string with format XX:XX:XX:XX:XX:XX to an hardware address
    pub fn from_str(s: String) -> Result<Self, ()> {
        let split: Vec<&str> = s.split(':').collect();

        if split.len() != COUNT_HWADDR_BYTES {
            return Err(())
        }

        let mut i = 0;
        let mut ret = Self::empty();

        for b in split {
            let bytes = b.as_bytes();

            if bytes.len() != 2 {
                return Err(())
            }

            let d1 = try!(b.char_at(0).to_digit(16).ok_or(())) * 16;
            let d2 = try!(b.char_at(1).to_digit(16).ok_or(()));

            ret.bytes[i] = d1 as u8 + d2 as u8;

            i += 1;
        }

        Ok(ret)
    }

    /// Create an hardware address from bytes.
    ///
    /// This method is unsafe because the slice *MUST* contain at least 6
    /// elements.
    pub unsafe fn from_bytes(bytes: &[u8]) -> Self {
        let mut ret = Self::empty();

        ret.bytes[0] = bytes[0];
        ret.bytes[1] = bytes[1];
        ret.bytes[2] = bytes[2];
        ret.bytes[3] = bytes[3];
        ret.bytes[4] = bytes[4];
        ret.bytes[5] = bytes[5];

        ret
    }

    #[inline]
    /// Returns the internal representation of an hardware address
    pub fn as_bytes(&self) -> &[u8] {
        &self.bytes[..]
    }
}

impl PartialEq for HwAddr {
    fn eq(&self, rhs: &Self) -> bool {
        self.bytes[0] == rhs.bytes[0] &&
        self.bytes[1] == rhs.bytes[1] &&
        self.bytes[2] == rhs.bytes[2] &&
        self.bytes[3] == rhs.bytes[3] &&
        self.bytes[4] == rhs.bytes[4] &&
        self.bytes[5] == rhs.bytes[5]
    }
}

impl Display for HwAddr {
    fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
        f.write_fmt(format_args!("{:02x}:{:02x}:{:02x}:{:02x}:{:02x}:{:02x}",
                                 self.bytes[0], self.bytes[1], self.bytes[2],
                                 self.bytes[3], self.bytes[4], self.bytes[5]))
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]

extern crate orbclient;
extern crate orbimage;

use std::cmp::max;
use std::env;

use orbclient::{Color, Renderer, Window, EventOption, K_ESC};
use orbimage::Image;

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(0, 0, 0));
        x += 8;
    }
}

fn main() {
    let url = match env::args().nth(1) {
        Some(arg) => arg,
        None => "/ui/background.png".to_string(),
    };

    match Image::from_path(&url) {
        Ok(image) => {
            let (width, height) = orbclient::get_display_size().expect("viewer: failed to get display size");
            println!("Display: {}, {}", width, height);

            println!("Image: {}, {}", image.width(), image.height());

            let best_width = width*3/4;
            let best_height = height*3/4;

            let d_w = best_width as f64;
            let d_h = best_height as f64;
            let i_w = image.width() as f64;
            let i_h = image.height() as f64;

            let scale = if d_w / d_h > i_w / i_h {
                d_h / i_h
            } else {
                d_w / i_w
            };

            let scaled_image = if scale < 1.0 {
                println!("Scale down {}", scale);
                image.resize((i_w * scale) as u32, (i_h * scale) as u32,
                             orbimage::ResizeType::Lanczos3).unwrap()
            } else {
                image.clone()
            };

            let mut window = Window::new(-1, -1, max(320, scaled_image.width()), max(240, scaled_image.height()),
                                         &("Viewer (".to_string() + &url + ")")).unwrap();

            let box_size = 4;
            for box_y in 0..window.height()/box_size {
                for box_x in 0..window.width()/box_size {
                    let color = if box_x % 2 == box_y % 2 {
                        Color::rgb(102, 102, 102)
                    }else{
                        Color::rgb(53, 53, 53)
                    };

                    window.rect((box_x * box_size) as i32, (box_y * box_size) as i32, box_size, box_size, color);
                }
            }

            let x = (window.width() - scaled_image.width())/2;
            let y = (window.height() - scaled_image.height())/2;
            scaled_image.draw(&mut window, x as i32, y as i32);
            window.sync();
            event_loop(&mut window);
        },
        Err(err) => {
            let msg = format!("{}", err);
            let mut window = Window::new(-1, -1, max(320, msg.len() as u32 * 8), 32,
                                         &("Viewer (".to_string() + &url + ")")).unwrap();
            window.set(Color::rgb(255, 255, 255));
            error_msg(&mut window, &msg);
            window.sync();
            event_loop(&mut window);
        }
    }
}
<commit_msg>Show scale of image<commit_after>#![deny(warnings)]

extern crate orbclient;
extern crate orbimage;

use std::cmp::max;
use std::env;

use orbclient::{Color, Renderer, Window, EventOption, K_ESC};
use orbimage::Image;

fn event_loop(window: &mut Window){
    loop {
        for event in window.events() {
            if let EventOption::Key(key_event) = event.to_option() {
                if key_event.pressed && key_event.scancode == K_ESC {
                    return;
                }
            }
            if let EventOption::Quit(_) = event.to_option() {
                return;
            }
        }
    }
}

fn error_msg(window: &mut Window, msg: &str) {
    let mut x = 0;
    for c in msg.chars() {
        window.char(x, 0, c, Color::rgb(0, 0, 0));
        x += 8;
    }
}

fn main() {
    let path = match env::args().nth(1) {
        Some(arg) => arg,
        None => "/ui/background.png".to_string(),
    };

    match Image::from_path(&path) {
        Ok(image) => {
            let (width, height) = orbclient::get_display_size().expect("viewer: failed to get display size");
            println!("Display: {}, {}", width, height);

            println!("Image: {}, {}", image.width(), image.height());

            let best_width = width*3/4;
            let best_height = height*3/4;

            let d_w = best_width as f64;
            let d_h = best_height as f64;
            let i_w = image.width() as f64;
            let i_h = image.height() as f64;

            let best_scale = if d_w / d_h > i_w / i_h {
                d_h / i_h
            } else {
                d_w / i_w
            };

            let (scaled_image, scale) = if best_scale < 1.0 {
                (image.resize((i_w * best_scale) as u32, (i_h * best_scale) as u32,
                             orbimage::ResizeType::Lanczos3).unwrap(), best_scale)
            } else {
                (image.clone(), 1.0)
            };

            let mut window = Window::new(-1, -1, max(320, scaled_image.width()), max(240, scaled_image.height()),
                                         &format!("{} - {:.1}% - Viewer", path, scale * 100.0)).unwrap();

            let box_size = 4;
            for box_y in 0..window.height()/box_size {
                for box_x in 0..window.width()/box_size {
                    let color = if box_x % 2 == box_y % 2 {
                        Color::rgb(102, 102, 102)
                    }else{
                        Color::rgb(53, 53, 53)
                    };

                    window.rect((box_x * box_size) as i32, (box_y * box_size) as i32, box_size, box_size, color);
                }
            }

            let x = (window.width() - scaled_image.width())/2;
            let y = (window.height() - scaled_image.height())/2;
            scaled_image.draw(&mut window, x as i32, y as i32);
            window.sync();
            event_loop(&mut window);
        },
        Err(err) => {
            let msg = format!("{}", err);
            let mut window = Window::new(-1, -1, max(320, msg.len() as u32 * 8), 32,
                                         &format!("{} - Viewer", path)).unwrap();
            window.set(Color::rgb(255, 255, 255));
            error_msg(&mut window, &msg);
            window.sync();
            event_loop(&mut window);
        }
    }
}
<|endoftext|>


<commit_before>// DOCS

#![allow(unstable)]
#![feature(plugin)]
#[plugin] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    parser::component(unfolded.as_slice())
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}
<commit_msg>Fix for static binaries?<commit_after>// DOCS

#![allow(unstable)]
#![feature(plugin)]
#[plugin] #[no_link] extern crate peg_syntax_ext;

use std::collections::HashMap;
use std::collections::hash_map::Entry::{Occupied, Vacant};

pub struct Property {
    /// Parameters.
    pub params: HashMap<String, String>,

    /// Value as unparsed string.
    pub raw_value: String,

    /// Property group. E.g. a contentline like `foo.FN:Markus` would result in the group being
    /// `"foo"`.
    pub prop_group: Option<String>
}

impl Property {
    /// Create property from unescaped string.
    pub fn new(value: &str) -> Property {
        Property {
            params: HashMap::new(),
            raw_value: escape_chars(value),
            prop_group: None
        }
    }

    /// Get value as unescaped string.
    pub fn value_as_string(&self) -> String {
        unescape_chars(self.raw_value.as_slice())
    }
}

pub struct Component {
    /// The name of the component, such as `VCARD` or `VEVENT`.
    pub name: String,

    /// The component's properties.
    pub props: HashMap<String, Vec<Property>>,

    /// The component's child- or sub-components.
    pub subcomponents: Vec<Component>
}

impl Component {
    pub fn new(name: &str) -> Component {
        Component {
            name: name.to_string(),
            props: HashMap::new(),
            subcomponents: vec![]
        }
    }

    /// Retrieve one property (from many) by key. Returns `None` if nothing is found.
    pub fn single_prop(&self, key: &str) -> Option<&Property> {
        match self.props.get(key) {
            Some(x) => {
                match x.len() {
                    1 => Some(&x[0]),
                    _ => None
                }
            },
            None => None
        }
    }

    /// Retrieve a mutable vector of properties for this key. Creates one (and inserts it into the
    /// component) if none exists.
    pub fn all_props_mut(&mut self, key: &str) -> &mut Vec<Property> {
        match self.props.entry(String::from_str(key)) {
            Occupied(values) => values.into_mut(),
            Vacant(values) => values.insert(vec![])
        }
    }

    /// Retrieve properties by key. Returns an empty slice if key doesn't exist.
    pub fn all_props(&self, key: &str) -> &[Property] {
        static EMPTY: &'static [Property] = &[];
        match self.props.get(key) {
            Some(values) => values.as_slice(),
            None => EMPTY
        }
    }
}

peg! parser(r#"
use super::{Component,Property};
use std::collections::HashMap;

components -> Vec<Component>
    = cs:component ** eols __ { cs }

    #[pub]
    component -> Component
        = name:component_begin
          ps:props
          cs:components
          component_end {
            let mut rv = Component::new(name);
            rv.subcomponents = cs;

            for (k, v) in ps.into_iter() {
                rv.all_props_mut(k).push(v);
            };

            rv
        }

    component_begin -> &'input str
        = "BEGIN:" v:value __ { v }

    component_end -> &'input str
        = "END:" v:value __ { v }

props -> Vec<(&'input str, Property)>
    = ps:prop ++ eols __ { ps }

    prop -> (&'input str, Property)
        = !"BEGIN:" !"END:" g:group? k:name p:params ":" v:value {
            (k, Property { params: p, raw_value: v.to_string(), prop_group: g })
        }

    group -> String
        = g:group_name "." { g.to_string() }

        group_name -> &'input str
            = group_char+ { match_str }

    name -> &'input str
        = iana_token+ { match_str }

    params -> HashMap<String, String>
        = ps:(";" p:param {p})* {
            let mut rv: HashMap<String, String> = HashMap::with_capacity(ps.len());
            rv.extend(ps.into_iter().map(|(k, v)| (k.to_string(), v.to_string())));
            rv
        }

        param -> (&'input str, &'input str)
            // FIXME: Doesn't handle comma-separated values
            = k:param_name v:("=" v:param_value { v })? {
                (k, match v {
                    Some(x) => x,
                    None => ""
                })
            }

        param_name -> &'input str
            = iana_token+ { match_str }

        param_value -> &'input str
            = x:(quoted_string / param_text) { x }

        param_text -> &'input str
            = safe_char* { match_str }

    value -> &'input str
        = value_char+ { match_str }

quoted_string -> &'input str
    = dquote x:quoted_content dquote { x }

quoted_content -> &'input str
    = qsafe_char* { match_str }

iana_token = ([a-zA-Z0-9] / "-")+
group_char = ([a-zA-Z0-9] / "-")
qsafe_char = !dquote !ctl value_char
safe_char = !";" !":" qsafe_char

value_char = !eol .

eol = "\r\n" / "\n" / "\r"
dquote = "\""
eols = eol+

// Taken from vCard. vCalendar's is a subset. Together with the definition of "qsafe_char" this
// might reject a bunch of valid iCalendars, but I can't imagine one.
ctl = [\u{00}-\u{1F}] / "\u{7F}"

whitespace = " " / "\t"
__ = (eol / whitespace)*

"#);

/// Parse a component. The error value is a human-readable message.
pub fn parse_component(s: &str) -> Result<Component, String> {
    // XXX: The unfolding should be worked into the PEG
    // See feature request: https://github.com/kevinmehall/rust-peg/issues/26
    let unfolded = unfold_lines(s);
    parser::component(unfolded.as_slice())
}

/// Write a component. The error value is a human-readable message.
pub fn write_component(c: &Component) -> String {
    fn inner(buf: &mut String, c: &Component) {
        buf.push_str("BEGIN:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");

        for (prop_name, props) in c.props.iter() {
            for prop in props.iter() {
                match prop.prop_group {
                    Some(ref x) => { buf.push_str(x.as_slice()); buf.push('.'); },
                    None => ()
                };
                buf.push_str(prop_name.as_slice());
                for (param_key, param_value) in prop.params.iter() {
                    buf.push(';');
                    buf.push_str(param_key.as_slice());
                    buf.push('=');
                    buf.push_str(param_value.as_slice());
                };
                buf.push(':');
                buf.push_str(fold_line(prop.raw_value.as_slice()).as_slice());
                buf.push_str("\r\n");
            };
        };

        for subcomponent in c.subcomponents.iter() {
            inner(buf, subcomponent);
        };

        buf.push_str("END:");
        buf.push_str(c.name.as_slice());
        buf.push_str("\r\n");
    }

    let mut buf = String::new();
    inner(&mut buf, c);
    buf
}

/// Escape text for a VObject property value.
pub fn escape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\n")
        .replace("\\", "\\\\")
        .replace(";", "\\;")
        .replace(",", "\\,")
        .replace("\r\n", "\\n")
        .replace("\n", "\\n")
}

/// Unescape text from a VObject property value.
pub fn unescape_chars(s: &str) -> String {
    // Order matters! Lifted from icalendar.parser
    // https://github.com/collective/icalendar/
    s
        .replace("\\N", "\\n")
        .replace("\r\n", "\n")
        .replace("\\n", "\n")
        .replace("\\,", ",")
        .replace("\\;", ";")
        .replace("\\\\", "\\")
}

/// Unfold contentline.
pub fn unfold_lines(s: &str) -> String {
    s
        .replace("\r\n ", "").replace("\r\n\t", "")
        .replace("\n ", "").replace("\n\t", "")
        .replace("\r ", "").replace("\r\t", "")
}

/// Fold contentline to 75 chars. This function assumes the input to be unfolded, which means no
/// '\n' or '\r' in it.
pub fn fold_line(s: &str) -> String {
    let mut rv = String::new();
    for (i, c) in s.chars().enumerate() {
        rv.push(c);
        if i != 0 && i % 75 == 0 {
            rv.push_str("\r\n ");
        };
    };
    rv
}
<|endoftext|>