<commit_before>use std::path::PathBuf;
use thiserror::Error;

/// Generic result type for functions in this crate with
/// a global error class.
pub type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Error, Debug, PartialEq)]
pub enum Error {
    // General errors
    #[error("file not found: {path}")]
    FileNotFound { path: PathBuf },
    #[error("invalid (non-unicode) characters in path")]
    NonUnicodePath,
    #[error("failed to fetch region")]
    Fetch,
    #[error("error seeking to file offset")]
    FileSeek,
    #[error("error seeking to {contig:?}:{start} in indexed file")]
    GenomicSeek { contig: String, start: u64 },
    #[error("sequence {sequence} not found in index")]
    UnknownSequence { sequence: String },
    #[error("error setting threads for file reading")]
    SetThreads,
    #[error("failed to create htslib thread pool")]
    ThreadPool,

    #[error("failed to write BAM/BCF record (out of disk space?)")]
    WriteRecord,

    // Errors for faidx
    #[error("The given position is too large to be converted to i64")]
    FaidxPositionTooLarge,

    // Errors for Tbx
    #[error("previous iterator generation failed")]
    TabixNoIter,
    #[error("truncated tabix record")]
    TabixTruncatedRecord,
    #[error("invalid tabix index")]
    TabixInvalidIndex,

    // Errors for BAM
    #[error("error parsing CIGAR string: {msg}")]
    BamParseCigar { msg: String },
    #[error("unexpected CIGAR operation: {msg}")]
    BamUnexpectedCigarOperation { msg: String },
    #[error("error parsing SAM record: {rec}")]
    BamParseSAM { rec: String },
    #[error("invalid path to CRAM-reference {path}")]
    BamInvalidReferencePath { path: PathBuf },
    #[error("invalid compression level {level}")]
    BamInvalidCompressionLevel { level: u32 },
    #[error("unable to open SAM/BAM/CRAM file at {target}")]
    BamOpen { target: String },
    #[error("unable to open SAM/BAM/CRAM index for {target}")]
    BamInvalidIndex { target: String },
    #[error("invalid record in SAM/BAM/CRAM file")]
    BamInvalidRecord,
    #[error("truncated record in SAM/BAM/CRAM file")]
    BamTruncatedRecord,
    #[error(
        "format not indexable by htslib (format is detected as something else than SAM/BAM/CRAM)"
    )]
    BamNotIndexable,
    #[error("failed to write BAM/CRAM index (out of disk space?)")]
    BamWriteIndex,
    #[error("failed to build BAM/CRAM index")]
    BamBuildIndex,
    #[error("failed to create SAM/BAM/CRAM pileup")]
    BamPileup,

    // Errors for BCF
    #[error("error allocating internal data structure for BCF/VCF reader (out of memory?)")]
    BcfAllocationError,
    #[error("failed to open BCF/VCF from {target:?}")]
    BcfOpen { target: String },
    #[error("invalid record in BCF/VCF file")]
    BcfInvalidRecord,
    #[error("tag {tag} undefined in BCF/VCF header")]
    BcfUndefinedTag { tag: String },
    #[error("unexpected type for tag {tag} in BCF/VCF file")]
    BcfUnexpectedType { tag: String },
    #[error("tag {tag} missing from record {record} in BCF/VCF file")]
    BcfMissingTag { tag: String, record: String },
    #[error("error setting tag {tag} in BCF/VCF record (out of memory?)")]
    BcfSetTag { tag: String },
    #[error("ID {rid} not found in BCF/VCF header")]
    BcfUnknownRID { rid: u32 },
    #[error("contig {contig} not found in BCF/VCF header")]
    BcfUnknownContig { contig: String },
    #[error("ID {id} not found in BCF/VCF header")]
    BcfUnknownID { id: String },
    #[error("sample {name} not found in BCF/VCF header")]
    BcfUnknownSample { name: String },
    #[error("duplicate sample names given for subsetting BCF/VCF")]
    BcfDuplicateSampleNames,
    #[error("failed to set values in BCF/VCF record (out of memory?)")]
    BcfSetValues,
    #[error("failed to remove alleles in BCF/VCF record")]
    BcfRemoveAlleles,
}
<commit_msg>more detailed error message for index loading error. (#303)<commit_after>use std::path::PathBuf;
use thiserror::Error;

/// Generic result type for functions in this crate with
/// a global error class.
pub type Result<T, E = Error> = std::result::Result<T, E>;

#[derive(Error, Debug, PartialEq)]
pub enum Error {
    // General errors
    #[error("file not found: {path}")]
    FileNotFound { path: PathBuf },
    #[error("invalid (non-unicode) characters in path")]
    NonUnicodePath,
    #[error("failed to fetch region")]
    Fetch,
    #[error("error seeking to file offset")]
    FileSeek,
    #[error("error seeking to {contig:?}:{start} in indexed file")]
    GenomicSeek { contig: String, start: u64 },
    #[error("sequence {sequence} not found in index")]
    UnknownSequence { sequence: String },
    #[error("error setting threads for file reading")]
    SetThreads,
    #[error("failed to create htslib thread pool")]
    ThreadPool,

    #[error("failed to write BAM/BCF record (out of disk space?)")]
    WriteRecord,

    // Errors for faidx
    #[error("The given position is too large to be converted to i64")]
    FaidxPositionTooLarge,

    // Errors for Tbx
    #[error("previous iterator generation failed")]
    TabixNoIter,
    #[error("truncated tabix record")]
    TabixTruncatedRecord,
    #[error("invalid tabix index")]
    TabixInvalidIndex,

    // Errors for BAM
    #[error("error parsing CIGAR string: {msg}")]
    BamParseCigar { msg: String },
    #[error("unexpected CIGAR operation: {msg}")]
    BamUnexpectedCigarOperation { msg: String },
    #[error("error parsing SAM record: {rec}")]
    BamParseSAM { rec: String },
    #[error("invalid path to CRAM-reference {path}")]
    BamInvalidReferencePath { path: PathBuf },
    #[error("invalid compression level {level}")]
    BamInvalidCompressionLevel { level: u32 },
    #[error("unable to open SAM/BAM/CRAM file at {target}")]
    BamOpen { target: String },
    #[error("unable to open SAM/BAM/CRAM index for {target}; please create an index")]
    BamInvalidIndex { target: String },
    #[error("invalid record in SAM/BAM/CRAM file")]
    BamInvalidRecord,
    #[error("truncated record in SAM/BAM/CRAM file")]
    BamTruncatedRecord,
    #[error(
        "format not indexable by htslib (format is detected as something else than SAM/BAM/CRAM)"
    )]
    BamNotIndexable,
    #[error("failed to write BAM/CRAM index (out of disk space?)")]
    BamWriteIndex,
    #[error("failed to build BAM/CRAM index")]
    BamBuildIndex,
    #[error("failed to create SAM/BAM/CRAM pileup")]
    BamPileup,

    // Errors for BCF
    #[error("error allocating internal data structure for BCF/VCF reader (out of memory?)")]
    BcfAllocationError,
    #[error("failed to open BCF/VCF from {target:?}")]
    BcfOpen { target: String },
    #[error("invalid record in BCF/VCF file")]
    BcfInvalidRecord,
    #[error("tag {tag} undefined in BCF/VCF header")]
    BcfUndefinedTag { tag: String },
    #[error("unexpected type for tag {tag} in BCF/VCF file")]
    BcfUnexpectedType { tag: String },
    #[error("tag {tag} missing from record {record} in BCF/VCF file")]
    BcfMissingTag { tag: String, record: String },
    #[error("error setting tag {tag} in BCF/VCF record (out of memory?)")]
    BcfSetTag { tag: String },
    #[error("ID {rid} not found in BCF/VCF header")]
    BcfUnknownRID { rid: u32 },
    #[error("contig {contig} not found in BCF/VCF header")]
    BcfUnknownContig { contig: String },
    #[error("ID {id} not found in BCF/VCF header")]
    BcfUnknownID { id: String },
    #[error("sample {name} not found in BCF/VCF header")]
    BcfUnknownSample { name: String },
    #[error("duplicate sample names given for subsetting BCF/VCF")]
    BcfDuplicateSampleNames,
    #[error("failed to set values in BCF/VCF record (out of memory?)")]
    BcfSetValues,
    #[error("failed to remove alleles in BCF/VCF record")]
    BcfRemoveAlleles,
}
<|endoftext|>


<commit_before>/*!
This module defines the various error types that can be produced by a failed conversion.
*/

use misc::{Saturated, InvalidSentinel, SignedInfinity};

/// Indicates that it is not possible for the conversion to fail.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct NoError;

/// Indicates that the conversion failed due to an underflow.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Underflow;

impl From<NoError> for Underflow {
    fn from(_: NoError) -> Underflow {
        panic!("cannot convert NoError into Underflow");
    }
}

/// Indicates that the conversion failed due to an overflow.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Overflow;

impl From<NoError> for Overflow {
    fn from(_: NoError) -> Overflow {
        panic!("cannot convert NoError into Overflow");
    }
}

/**
Indicates that a conversion from a floating point type failed.
*/
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum FloatError {
    /// Input underflowed the target type.
    Underflow,

    /// Input overflowed the target type.
    Overflow,

    /// Input was not-a-number, which the target type could not represent.
    NotANumber,
}

impl From<NoError> for FloatError {
    fn from(_: NoError) -> FloatError {
        panic!("cannot convert NoError into FloatError");
    }
}

impl From<Underflow> for FloatError {
    fn from(_: Underflow) -> FloatError {
        FloatError::Underflow
    }
}

impl From<Overflow> for FloatError {
    fn from(_: Overflow) -> FloatError {
        FloatError::Overflow
    }
}

impl From<RangeError> for FloatError {
    fn from(e: RangeError) -> FloatError {
        use self::RangeError as R;
        use self::FloatError as F;
        match e {
            R::Underflow => F::Underflow,
            R::Overflow => F::Overflow,
        }
    }
}

/**
Indicates that a conversion failed due to a range error.
*/
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum RangeError {
    /// Input underflowed the target type.
    Underflow,

    /// Input overflowed the target type.
    Overflow,
}

impl From<NoError> for RangeError {
    fn from(_: NoError) -> RangeError {
        panic!("cannot convert NoError into RangeError");
    }
}

impl From<Underflow> for RangeError {
    fn from(_: Underflow) -> RangeError {
        RangeError::Underflow
    }
}

impl From<Overflow> for RangeError {
    fn from(_: Overflow) -> RangeError {
        RangeError::Overflow
    }
}

/**
Unwrap a conversion by saturating to infinity.
*/
pub trait UnwrapOrInf {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or saturates to infinity in the "direction" of overflow/underflow.
    */
    fn unwrap_or_inf(self) -> Self::Output;
}

/**
Unwrap a conversion by replacing a failure with an invalid sentinel value.
*/
pub trait UnwrapOrInvalid {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or returns the output type's invalid sentinel value.
    */
    fn unwrap_or_invalid(self) -> Self::Output;
}

/**
Unwrap a conversion by saturating.
*/
pub trait UnwrapOrSaturate {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or saturates in the "direction" of overflow/underflow.
    */
    fn unwrap_or_saturate(self) -> Self::Output;
}

impl<T, E> UnwrapOrInf for Result<T, E>
where T: SignedInfinity, E: Into<RangeError> {
    type Output = T;
    fn unwrap_or_inf(self) -> T {
        use self::RangeError::*;
        match self.map_err(Into::into) {
            Ok(v) => v,
            Err(Underflow) => T::neg_infinity(),
            Err(Overflow) => T::pos_infinity(),
        }
    }
}

impl<T, E> UnwrapOrInvalid for Result<T, E>
where T: InvalidSentinel {
    type Output = T;
    fn unwrap_or_invalid(self) -> T {
        match self {
            Ok(v) => v,
            Err(..) => T::invalid_sentinel(),
        }
    }
}

impl<T, E> UnwrapOrSaturate for Result<T, E>
where T: Saturated, E: Into<RangeError> {
    type Output = T;
    fn unwrap_or_saturate(self) -> T {
        use self::RangeError::*;
        match self.map_err(Into::into) {
            Ok(v) => v,
            Err(Underflow) => T::saturated_min(),
            Err(Overflow) => T::saturated_max(),
        }
    }
}
<commit_msg>Changed `NoError` to an empty type.<commit_after>/*!
This module defines the various error types that can be produced by a failed conversion.
*/

use misc::{Saturated, InvalidSentinel, SignedInfinity};

/// Indicates that it is not possible for the conversion to fail.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum NoError {}

/// Indicates that the conversion failed due to an underflow.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Underflow;

impl From<NoError> for Underflow {
    fn from(_: NoError) -> Underflow {
        panic!("cannot convert NoError into Underflow");
    }
}

/// Indicates that the conversion failed due to an overflow.
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub struct Overflow;

impl From<NoError> for Overflow {
    fn from(_: NoError) -> Overflow {
        panic!("cannot convert NoError into Overflow");
    }
}

/**
Indicates that a conversion from a floating point type failed.
*/
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum FloatError {
    /// Input underflowed the target type.
    Underflow,

    /// Input overflowed the target type.
    Overflow,

    /// Input was not-a-number, which the target type could not represent.
    NotANumber,
}

impl From<NoError> for FloatError {
    fn from(_: NoError) -> FloatError {
        panic!("cannot convert NoError into FloatError");
    }
}

impl From<Underflow> for FloatError {
    fn from(_: Underflow) -> FloatError {
        FloatError::Underflow
    }
}

impl From<Overflow> for FloatError {
    fn from(_: Overflow) -> FloatError {
        FloatError::Overflow
    }
}

impl From<RangeError> for FloatError {
    fn from(e: RangeError) -> FloatError {
        use self::RangeError as R;
        use self::FloatError as F;
        match e {
            R::Underflow => F::Underflow,
            R::Overflow => F::Overflow,
        }
    }
}

/**
Indicates that a conversion failed due to a range error.
*/
#[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Debug)]
pub enum RangeError {
    /// Input underflowed the target type.
    Underflow,

    /// Input overflowed the target type.
    Overflow,
}

impl From<NoError> for RangeError {
    fn from(_: NoError) -> RangeError {
        panic!("cannot convert NoError into RangeError");
    }
}

impl From<Underflow> for RangeError {
    fn from(_: Underflow) -> RangeError {
        RangeError::Underflow
    }
}

impl From<Overflow> for RangeError {
    fn from(_: Overflow) -> RangeError {
        RangeError::Overflow
    }
}

/**
Unwrap a conversion by saturating to infinity.
*/
pub trait UnwrapOrInf {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or saturates to infinity in the "direction" of overflow/underflow.
    */
    fn unwrap_or_inf(self) -> Self::Output;
}

/**
Unwrap a conversion by replacing a failure with an invalid sentinel value.
*/
pub trait UnwrapOrInvalid {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or returns the output type's invalid sentinel value.
    */
    fn unwrap_or_invalid(self) -> Self::Output;
}

/**
Unwrap a conversion by saturating.
*/
pub trait UnwrapOrSaturate {
    /// The result of unwrapping.
    type Output;

    /**
    Either unwraps the successfully converted value, or saturates in the "direction" of overflow/underflow.
    */
    fn unwrap_or_saturate(self) -> Self::Output;
}

impl<T, E> UnwrapOrInf for Result<T, E>
where T: SignedInfinity, E: Into<RangeError> {
    type Output = T;
    fn unwrap_or_inf(self) -> T {
        use self::RangeError::*;
        match self.map_err(Into::into) {
            Ok(v) => v,
            Err(Underflow) => T::neg_infinity(),
            Err(Overflow) => T::pos_infinity(),
        }
    }
}

impl<T, E> UnwrapOrInvalid for Result<T, E>
where T: InvalidSentinel {
    type Output = T;
    fn unwrap_or_invalid(self) -> T {
        match self {
            Ok(v) => v,
            Err(..) => T::invalid_sentinel(),
        }
    }
}

impl<T, E> UnwrapOrSaturate for Result<T, E>
where T: Saturated, E: Into<RangeError> {
    type Output = T;
    fn unwrap_or_saturate(self) -> T {
        use self::RangeError::*;
        match self.map_err(Into::into) {
            Ok(v) => v,
            Err(Underflow) => T::saturated_min(),
            Err(Overflow) => T::saturated_max(),
        }
    }
}
<|endoftext|>


<commit_before>extern crate r2d2;

quick_error! {
    /// The most generic error message in ReQL
    #[derive(Debug)]
    pub enum Error {
        Compile(descr: &'static str) { }
        Runtime(err: RuntimeError) { from() }
        Driver(err: DriverError) { from() }
    }
}

quick_error! {
    /// The parent class of all runtime errors
    ///
    /// All errors on the server unrelated to compilation. Programs may use this to catch any runtime
    /// error, but the server will always return a more specific error class.
    #[derive(Debug)]
    pub enum RuntimeError {
        QueryLogic(err: QueryLogicError) { from() }
        ResourceLimit(descr: &'static str) {}
        User(descr: &'static str) {}
        Internal(descr: &'static str) {}
        Timeout(descr: &'static str) {}
        Availability(err: AvailabilityError) { from() }
        Permissions(descr: &'static str) {}
    }
}

quick_error! {
    /// The query contains a logical impossibility, such as adding a number to a string.
    #[derive(Debug)]
    pub enum QueryLogicError {
        NonExistence(descr: &'static str) {}
    }
}

quick_error! {
    /// A server in the cluster is unavailable
    ///
    /// The parent class of `OpFailedError` and `OpIndeterminateError`. Programs may use this
    /// to catch any availability error, but the server will always return one of this class’s
    /// children.
    #[derive(Debug)]
    pub enum AvailabilityError {
        OpFailed(descr: &'static str) {}
        OpIndeterminate(descr: &'static str) {}
    }
}

quick_error! {
    /// An error has occurred within the driver
    ///
    /// This may be a driver bug, or it may be an unfulfillable command, such as an unserializable
    /// query.
    #[derive(Debug)]
    pub enum DriverError {
        Auth(descr: &'static str) {}
        Initialization(err: r2d2::InitializationError) { from() }
        Connection(err: ConnectionError) { from() }
    }
}

quick_error! {
    /// Connection related errors
    #[derive(Debug)]
    pub enum ConnectionError {
        PoolWrite(descr: &'static str) {}
        PoolRead(descr: &'static str) {}
    }
}

/// Converts external error to ours
impl From<r2d2::InitializationError> for Error {
    fn from(err: r2d2::InitializationError) -> Error {
        From::from(DriverError::Initialization(err))
    }
}

impl From<ConnectionError> for Error {
    fn from(err: ConnectionError) -> Error {
        From::from(DriverError::Connection(err))
    }
}
<commit_msg>Accept error messages as Strings<commit_after>extern crate r2d2;

quick_error! {
    /// The most generic error message in ReQL
    #[derive(Debug)]
    pub enum Error {
        Compile(descr: String) { }
        Runtime(err: RuntimeError) { from() }
        Driver(err: DriverError) { from() }
    }
}

quick_error! {
    /// The parent class of all runtime errors
    ///
    /// All errors on the server unrelated to compilation. Programs may use this to catch any runtime
    /// error, but the server will always return a more specific error class.
    #[derive(Debug)]
    pub enum RuntimeError {
        QueryLogic(err: QueryLogicError) { from() }
        ResourceLimit(descr: String) {}
        User(descr: String) {}
        Internal(descr: String) {}
        Timeout(descr: String) {}
        Availability(err: AvailabilityError) { from() }
        Permissions(descr: String) {}
    }
}

quick_error! {
    /// The query contains a logical impossibility, such as adding a number to a string.
    #[derive(Debug)]
    pub enum QueryLogicError {
        NonExistence(descr: String) {}
    }
}

quick_error! {
    /// A server in the cluster is unavailable
    ///
    /// The parent class of `OpFailedError` and `OpIndeterminateError`. Programs may use this
    /// to catch any availability error, but the server will always return one of this class’s
    /// children.
    #[derive(Debug)]
    pub enum AvailabilityError {
        OpFailed(descr: String) {}
        OpIndeterminate(descr: String) {}
    }
}

quick_error! {
    /// An error has occurred within the driver
    ///
    /// This may be a driver bug, or it may be an unfulfillable command, such as an unserializable
    /// query.
    #[derive(Debug)]
    pub enum DriverError {
        Auth(descr: String) {}
        Initialization(err: r2d2::InitializationError) { from() }
        Connection(err: ConnectionError) { from() }
    }
}

quick_error! {
    /// Connection related errors
    #[derive(Debug)]
    pub enum ConnectionError {
        PoolWrite(descr: String) {}
        PoolRead(descr: String) {}
    }
}

/// Converts external error to ours
impl From<r2d2::InitializationError> for Error {
    fn from(err: r2d2::InitializationError) -> Error {
        From::from(DriverError::Initialization(err))
    }
}

impl From<ConnectionError> for Error {
    fn from(err: ConnectionError) -> Error {
        From::from(DriverError::Connection(err))
    }
}
<|endoftext|>


<commit_before>//! Manage xml character escapes

use std::borrow::Cow;
use errors::Result;
use errors::ErrorKind::Escape;
use memchr;

// UTF-8 ranges and tags for encoding characters
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;

enum ByteOrChar {
    Byte(u8),
    Char(u32),
}

/// helper function to escape a `&[u8]` and replace all
/// xml special characters (<, >, &, ', ") with their corresponding
/// xml escaped value.
pub fn escape(raw: &[u8]) -> Cow<[u8]> {
    let mut escapes: Vec<(usize, &'static [u8])> = Vec::new();
    let mut bytes = raw.iter();
    fn to_escape(b: u8) -> bool {
        match b {
            b'<' | b'>' | b'\'' | b'&' | b'"' => true,
            _ => false,
        }
    }

    let mut loc = 0;
    while let Some(i) = bytes.position(|&b| to_escape(b)) {
        loc += i;
        match raw[loc] {
            b'<' => escapes.push((loc, b"<")),
            b'>' => escapes.push((loc, b">")),
            b'\'' => escapes.push((loc, b"'")),
            b'&' => escapes.push((loc, b"&")),
            b'"' => escapes.push((loc, b""")),
            _ => unreachable!("Only '<', '>','\', '&' and '\"' are escaped"),
        }
        loc += 1;
    }

    if escapes.is_empty() {
        Cow::Borrowed(raw)
    } else {
        let len = raw.len();
        let mut v = Vec::with_capacity(len);
        let mut start = 0;
        for (i, r) in escapes {
            v.extend_from_slice(&raw[start..i]);
            v.extend_from_slice(r);
            start = i + 1;
        }

        if start < len {
            v.extend_from_slice(&raw[start..]);
        }
        Cow::Owned(v)
    }
}

/// helper function to unescape a `&[u8]` and replace all
/// xml escaped characters ('&...;') into their corresponding value
pub fn unescape(raw: &[u8]) -> Result<Cow<[u8]>> {
    let mut escapes = Vec::new();

    let mut start = 0;
    while let Some(i) = memchr::memchr(b'&', &raw[start..]) {
        start += i + 1;
        if let Some(j) = memchr::memchr(b';', &raw[start..]) {
            let end = start + j;
            // search for character correctness
            let b_o_c = match &raw[start..end] {
                b"lt" => ByteOrChar::Byte(b'<'),
                b"gt" => ByteOrChar::Byte(b'>'),
                b"amp" => ByteOrChar::Byte(b'&'),
                b"apos" => ByteOrChar::Byte(b'\''),
                b"quot" => ByteOrChar::Byte(b'\"'),
                b"#x0" | b"#0" => bail!(Escape(
                    "Null character entity not allowed".to_string(),
                    start..end
                )),
                bytes if bytes.starts_with(b"#x") => {
                    ByteOrChar::Char(parse_hexadecimal(&bytes[2..])?)
                }
                bytes if bytes.starts_with(b"#") => ByteOrChar::Char(parse_decimal(&bytes[1..])?),
                bytes => bail!(Escape(
                    format!(
                        "Unrecognized escape symbol: {:?}",
                        ::std::str::from_utf8(bytes)
                    ),
                    start..end
                )),
            };
            escapes.push((start - 1..end, b_o_c));
            start = end + 1;
        } else {
            bail!(Escape(
                "Cannot find ';' after '&'".to_string(),
                start..raw.len()
            ));
        }
    }
    if escapes.is_empty() {
        Ok(Cow::Borrowed(raw))
    } else {
        let len = raw.len();
        let mut v = Vec::with_capacity(len);
        let mut start = 0;
        for (r, b) in escapes {
            v.extend_from_slice(&raw[start..r.start]);
            match b {
                ByteOrChar::Byte(b) => v.push(b),
                ByteOrChar::Char(c) => push_utf8(&mut v, c),
            }
            start = r.end + 1;
        }
        if start < raw.len() {
            v.extend_from_slice(&raw[start..]);
        }
        Ok(Cow::Owned(v))
    }
}

fn push_utf8(buf: &mut Vec<u8>, code: u32) {
    if code < MAX_ONE_B {
        buf.push(code as u8);
    } else if code < MAX_TWO_B {
        buf.push((code >> 6 & 0x1F) as u8 | TAG_TWO_B);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    } else if code < MAX_THREE_B {
        buf.push((code >> 12 & 0x0F) as u8 | TAG_THREE_B);
        buf.push((code >> 6 & 0x3F) as u8 | TAG_CONT);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    } else {
        buf.push((code >> 18 & 0x07) as u8 | TAG_FOUR_B);
        buf.push((code >> 12 & 0x3F) as u8 | TAG_CONT);
        buf.push((code >> 6 & 0x3F) as u8 | TAG_CONT);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    }
}

fn parse_hexadecimal(bytes: &[u8]) -> Result<u32> {
    // maximum code is character is 0x10FFFF => 6 characters
    if bytes.len() > 6 {
        bail!("Cannot convert hexadecimal to utf8");
    }
    let mut code = 0;
    for &b in bytes {
        code <<= 4;
        code += match b {
            b'0'...b'9' => b - b'0',
            b'a'...b'f' => b - b'a' + 10,
            b'A'...b'F' => b - b'A' + 10,
            b => bail!("'{}' is not a valid hexadecimal character", b as char),
        } as u32;
    }
    Ok(code)
}

fn parse_decimal(bytes: &[u8]) -> Result<u32> {
    // maximum code is character is 0x10FFFF = 1114111 => 7 characters
    if bytes.len() > 7 {
        bail!("Cannot convert decimal to utf8");
    }
    let mut code = 0;
    for &b in bytes {
        code *= 10;
        code += match b {
            b'0'...b'9' => b - b'0',
            b => bail!("'{}' is not a valid decimal character", b as char),
        } as u32;
    }
    Ok(code)
}

#[test]
fn test_unescape() {
    assert_eq!(&*unescape(b"test").unwrap(), b"test");
    assert_eq!(&*unescape(b"<test>").unwrap(), b"<test>");
    assert_eq!(&*unescape(b"0").unwrap(), b"0");
    assert_eq!(&*unescape(b"0").unwrap(), b"0");
}

#[test]
fn test_escape() {
    assert_eq!(&*escape(b"test"), b"test");
    assert_eq!(&*escape(b"<test>"), b"<test>");
    assert_eq!(&*escape(b"\"a\"bc"), b""a"bc");
    assert_eq!(&*escape(b"\"a\"b&c"), b""a"b&c");
    assert_eq!(
        &*escape(b"prefix_\"a\"b&<>c"),
        "prefix_"a"b&<>c".as_bytes()
    );
}
<commit_msg>change comments<commit_after>//! Manage xml character escapes

use std::borrow::Cow;
use errors::Result;
use errors::ErrorKind::Escape;
use memchr;

// UTF-8 ranges and tags for encoding characters
const TAG_CONT: u8 = 0b1000_0000;
const TAG_TWO_B: u8 = 0b1100_0000;
const TAG_THREE_B: u8 = 0b1110_0000;
const TAG_FOUR_B: u8 = 0b1111_0000;
const MAX_ONE_B: u32 = 0x80;
const MAX_TWO_B: u32 = 0x800;
const MAX_THREE_B: u32 = 0x10000;

enum ByteOrChar {
    Byte(u8),
    Char(u32),
}

/// helper function to escape a `&[u8]` and replace all
/// xml special characters (<, >, &, ', ") with their corresponding
/// xml escaped value.
pub fn escape(raw: &[u8]) -> Cow<[u8]> {
    let mut escapes: Vec<(usize, &'static [u8])> = Vec::new();
    let mut bytes = raw.iter();
    fn to_escape(b: u8) -> bool {
        match b {
            b'<' | b'>' | b'\'' | b'&' | b'"' => true,
            _ => false,
        }
    }

    let mut loc = 0;
    while let Some(i) = bytes.position(|&b| to_escape(b)) {
        loc += i;
        match raw[loc] {
            b'<' => escapes.push((loc, b"<")),
            b'>' => escapes.push((loc, b">")),
            b'\'' => escapes.push((loc, b"'")),
            b'&' => escapes.push((loc, b"&")),
            b'"' => escapes.push((loc, b""")),
            _ => unreachable!("Only '<', '>','\', '&' and '\"' are escaped"),
        }
        loc += 1;
    }

    if escapes.is_empty() {
        Cow::Borrowed(raw)
    } else {
        let len = raw.len();
        let mut v = Vec::with_capacity(len);
        let mut start = 0;
        for (i, r) in escapes {
            v.extend_from_slice(&raw[start..i]);
            v.extend_from_slice(r);
            start = i + 1;
        }

        if start < len {
            v.extend_from_slice(&raw[start..]);
        }
        Cow::Owned(v)
    }
}

/// helper function to unescape a `&[u8]` and replace all
/// xml escaped characters ('&...;') into their corresponding value
pub fn unescape(raw: &[u8]) -> Result<Cow<[u8]>> {
    let mut escapes = Vec::new();

    let mut start = 0;
    while let Some(i) = memchr::memchr(b'&', &raw[start..]) {
        start += i + 1;
        if let Some(j) = memchr::memchr(b';', &raw[start..]) {
            let end = start + j;
            // search for character correctness
            let b_o_c = match &raw[start..end] {
                b"lt" => ByteOrChar::Byte(b'<'),
                b"gt" => ByteOrChar::Byte(b'>'),
                b"amp" => ByteOrChar::Byte(b'&'),
                b"apos" => ByteOrChar::Byte(b'\''),
                b"quot" => ByteOrChar::Byte(b'\"'),
                b"#x0" | b"#0" => bail!(Escape(
                    "Null character entity not allowed".to_string(),
                    start..end
                )),
                bytes if bytes.starts_with(b"#x") => {
                    ByteOrChar::Char(parse_hexadecimal(&bytes[2..])?)
                }
                bytes if bytes.starts_with(b"#") => ByteOrChar::Char(parse_decimal(&bytes[1..])?),
                bytes => bail!(Escape(
                    format!(
                        "Unrecognized escape symbol: {:?}",
                        ::std::str::from_utf8(bytes)
                    ),
                    start..end
                )),
            };
            escapes.push((start - 1..end, b_o_c));
            start = end + 1;
        } else {
            bail!(Escape(
                "Cannot find ';' after '&'".to_string(),
                start..raw.len()
            ));
        }
    }
    if escapes.is_empty() {
        Ok(Cow::Borrowed(raw))
    } else {
        let len = raw.len();
        let mut v = Vec::with_capacity(len);
        let mut start = 0;
        for (r, b) in escapes {
            v.extend_from_slice(&raw[start..r.start]);
            match b {
                ByteOrChar::Byte(b) => v.push(b),
                ByteOrChar::Char(c) => push_utf8(&mut v, c),
            }
            start = r.end + 1;
        }
        if start < raw.len() {
            v.extend_from_slice(&raw[start..]);
        }
        Ok(Cow::Owned(v))
    }
}

fn push_utf8(buf: &mut Vec<u8>, code: u32) {
    if code < MAX_ONE_B {
        buf.push(code as u8);
    } else if code < MAX_TWO_B {
        buf.push((code >> 6 & 0x1F) as u8 | TAG_TWO_B);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    } else if code < MAX_THREE_B {
        buf.push((code >> 12 & 0x0F) as u8 | TAG_THREE_B);
        buf.push((code >> 6 & 0x3F) as u8 | TAG_CONT);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    } else {
        buf.push((code >> 18 & 0x07) as u8 | TAG_FOUR_B);
        buf.push((code >> 12 & 0x3F) as u8 | TAG_CONT);
        buf.push((code >> 6 & 0x3F) as u8 | TAG_CONT);
        buf.push((code & 0x3F) as u8 | TAG_CONT);
    }
}

fn parse_hexadecimal(bytes: &[u8]) -> Result<u32> {
    // maximum code is 0x10FFFF => 6 characters
    if bytes.len() > 6 {
        bail!("Cannot convert hexadecimal to utf8");
    }
    let mut code = 0;
    for &b in bytes {
        code <<= 4;
        code += match b {
            b'0'...b'9' => b - b'0',
            b'a'...b'f' => b - b'a' + 10,
            b'A'...b'F' => b - b'A' + 10,
            b => bail!("'{}' is not a valid hexadecimal character", b as char),
        } as u32;
    }
    Ok(code)
}

fn parse_decimal(bytes: &[u8]) -> Result<u32> {
    // maximum code is 0x10FFFF = 1114111 => 7 characters
    if bytes.len() > 7 {
        bail!("Cannot convert decimal to utf8");
    }
    let mut code = 0;
    for &b in bytes {
        code *= 10;
        code += match b {
            b'0'...b'9' => b - b'0',
            b => bail!("'{}' is not a valid decimal character", b as char),
        } as u32;
    }
    Ok(code)
}

#[test]
fn test_unescape() {
    assert_eq!(&*unescape(b"test").unwrap(), b"test");
    assert_eq!(&*unescape(b"<test>").unwrap(), b"<test>");
    assert_eq!(&*unescape(b"0").unwrap(), b"0");
    assert_eq!(&*unescape(b"0").unwrap(), b"0");
}

#[test]
fn test_escape() {
    assert_eq!(&*escape(b"test"), b"test");
    assert_eq!(&*escape(b"<test>"), b"<test>");
    assert_eq!(&*escape(b"\"a\"bc"), b""a"bc");
    assert_eq!(&*escape(b"\"a\"b&c"), b""a"b&c");
    assert_eq!(
        &*escape(b"prefix_\"a\"b&<>c"),
        "prefix_"a"b&<>c".as_bytes()
    );
}
<|endoftext|>


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

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

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

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

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

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

		string
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

	pub annotations_enabled: bool,

	pub mapping_enabled: bool,
}

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

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

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

		string
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


<commit_before>pub use ops::and::And;
pub use ops::not::Not;
pub use ops::or::Or;

pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

pub trait Filter<N> {

    fn filter(&self, &N) -> bool;

    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

}
<commit_msg>Add test for iterator filtering<commit_after>pub use ops::and::And;
pub use ops::not::Not;
pub use ops::or::Or;

pub trait IntoFilter<N> {
    type IntoFilt: Filter<N>;

    fn into_filter(self) -> Self::IntoFilt;
}

impl<N, I: Filter<N>> IntoFilter<N> for I {
    type IntoFilt = I;

    fn into_filter(self) -> I {
        self
    }
}

impl<I, T: Fn(&I) -> bool> Filter<I> for T {
    fn filter(&self, other: &I) -> bool {
        self(other)
    }
}

pub trait Filter<N> {

    fn filter(&self, &N) -> bool;

    fn not(self) -> Not<Self>
        where Self: Sized
    {
        Not::new(self)
    }

    fn or<F>(self, other: F) -> Or<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        Or::new(self, other.into_filter())
    }

    fn or_not<F>(self, other: F) -> Or<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
    {
        self.or(Not::new(other.into_filter()))
    }

    fn or3<F, F2>(self, other: F, other2: F2) -> Or<Self, Or<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        Or::new(self, Or::new(other.into_filter(), other2.into_filter()))
    }

    fn and<F>(self, other: F) -> And<Self, F::IntoFilt>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        And::new(self, other.into_filter())
    }

    fn and3<F, F2>(self, other: F, other2: F2) -> And<Self, And<F::IntoFilt, F2::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized,
              F2: IntoFilter<N> + Sized
    {
        And::new(self, And::new(other.into_filter(), other2.into_filter()))
    }

    fn and_not<F>(self, other: F) -> And<Self, Not<F::IntoFilt>>
        where Self: Sized,
              F: IntoFilter<N> + Sized
    {
        self.and(Not::new(other.into_filter()))
    }

}

#[cfg(test)]
mod test {
    use filter::Filter;
    use ops::and::And;

    #[test]
    fn closures() {
        let a = (|&a: &usize|{ a < 3 }).and(|&a: &usize| a > 1);

        assert_eq!(a.filter(&2), true);
    }

    #[test]
    fn and_filter() {
        let a = And::new(|&a: &usize| a > 0, |&a: &usize| a == 3);

        assert_eq!(a.filter(&3),  true);
        assert_eq!(a.filter(&5),  false);
        assert_eq!(a.filter(&0), false);
    }

    #[test]
    fn complex_filter() {
        let a = (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20) ) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_closured() {
        let a = (|&a: &usize| (|&a: &usize|{ a > 5 }).and_not(|&a: &usize| a < 20).filter(&a)).or(|&a: &usize| a == 10);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&11), false);
        assert_eq!(a.filter(&5), false);
    }

    #[test]
    fn complex_filter_named_closures() {
        let not_eq_to_one   = |&a: &usize| { a != 1 };
        let not_eq_to_two   = |&a: &usize| { a != 2 };
        let not_eq_to_three = |&a: &usize| { a != 3 };

        let a = not_eq_to_one.and(not_eq_to_two).and(not_eq_to_three);
        // We now have ((a > 5) && !(a < 20)) || a == 10

        assert_eq!(a.filter(&21), true);
        assert_eq!(a.filter(&10), true);
        assert_eq!(a.filter(&1), false);
        assert_eq!(a.filter(&3), false);
    }

    struct EqTo {
        pub i: usize,
    }

    impl Filter<usize> for EqTo {
        fn filter(&self, n: &usize) -> bool {
            self.i == *n
        }
    }

    #[test]
    fn filter_with_eqto() {
        let eq = EqTo { i: 0 };
        assert_eq!(eq.filter(&0),  true);
        assert_eq!(eq.filter(&1),  false);
        assert_eq!(eq.filter(&17), false);
        assert_eq!(eq.filter(&42), false);
    }

    #[test]
    fn filter_with_combined_eqto() {
        let aeq = EqTo { i: 1 }.not().and_not(EqTo { i: 17 });

        assert_eq!(aeq.filter(&0),  true);
        assert_eq!(aeq.filter(&1),  false);
        assert_eq!(aeq.filter(&2),  true);
        assert_eq!(aeq.filter(&17), false);
    }

    #[test]
    fn filter_iterator() {
        let v = vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20];

        let inrange        = (|&a: &usize| { a > 5 }).and(|&a: &usize| { a < 15 });

        let r : Vec<usize> = v.into_iter().filter(|x| inrange.filter(x)).collect();

        assert_eq!(r, vec![6, 7, 8, 9, 10, 11, 12, 13, 14]);
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display};
use std::mem;
use std::str::FromStr;

use proc_macro2::Span;
use syn::{File, Ident, Item, ItemConst, ItemFn, ItemMod, ItemType, TraitItem, Visibility};

#[derive(Debug)]
pub struct Filter {
    segments: Vec<Ident>,
}

impl FromStr for Filter {
    type Err = String;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut segments = Vec::new();
        for segment in input.split("::") {
            match syn::parse_str(segment) {
                Ok(ident) => segments.push(ident),
                Err(_) => return Err(format!("`{}` is not an identifier", segment)),
            }
        }
        if segments.is_empty() {
            return Err("empty path".to_owned());
        }
        Ok(Filter { segments })
    }
}

impl Display for Filter {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        for (i, segment) in self.segments.iter().enumerate() {
            if i > 0 {
                formatter.write_str("::")?;
            }
            Display::fmt(segment, formatter)?;
        }
        Ok(())
    }
}

pub fn filter(syntax_tree: &mut File, filter: &Filter) {
    syntax_tree.shebang = None;
    syntax_tree.attrs.clear();

    let items = mem::replace(&mut syntax_tree.items, Vec::new());
    let root_mod = ItemMod {
        attrs: Vec::new(),
        vis: Visibility::Inherited,
        mod_token: Default::default(),
        ident: Ident::new("root", Span::call_site()),
        content: Some((Default::default(), items)),
        semi: None,
    };
    let mut items = vec![Item::Mod(root_mod)];

    for segment in &filter.segments {
        items = items
            .into_iter()
            .flat_map(enter_item)
            .filter(|item| name_of_item(item) == Some(segment))
            .collect();
    }

    if items.len() == 1 {
        items = match items.pop().unwrap() {
            Item::Mod(ItemMod {
                content: Some((_, nested)),
                ..
            }) => nested,
            other => vec![other],
        };
    }

    syntax_tree.items = items;
}

fn enter_item(item: Item) -> Vec<Item> {
    match item {
        Item::ExternCrate(_) => Vec::new(),
        Item::Use(_) => Vec::new(),
        Item::Static(_) => Vec::new(),
        Item::Const(_) => Vec::new(),
        Item::Fn(_) => Vec::new(),
        Item::Mod(item_mod) => match item_mod.content {
            Some((_, nested)) => nested,
            None => Vec::new(),
        },
        Item::ForeignMod(_) => Vec::new(),
        Item::Type(_) => Vec::new(),
        Item::Existential(_) => Vec::new(),
        Item::Struct(_) => Vec::new(),
        Item::Enum(_) => Vec::new(),
        Item::Union(_) => Vec::new(),
        Item::Trait(item_trait) => item_trait
            .items
            .into_iter()
            .filter_map(|trait_item| match trait_item {
                TraitItem::Const(item) => Some(Item::Const(ItemConst {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    const_token: item.const_token,
                    ident: item.ident,
                    colon_token: item.colon_token,
                    ty: Box::new(item.ty),
                    eq_token: item.default.as_ref()?.0,
                    expr: Box::new(item.default?.1),
                    semi_token: item.semi_token,
                })),
                TraitItem::Method(item) => Some(Item::Fn(ItemFn {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    constness: item.sig.constness,
                    unsafety: item.sig.unsafety,
                    asyncness: item.sig.asyncness,
                    abi: item.sig.abi,
                    ident: item.sig.ident,
                    decl: Box::new(item.sig.decl),
                    block: Box::new(item.default?),
                })),
                TraitItem::Type(item) => Some(Item::Type(ItemType {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    type_token: item.type_token,
                    ident: item.ident,
                    generics: item.generics,
                    eq_token: item.default.as_ref()?.0,
                    ty: Box::new(item.default?.1),
                    semi_token: item.semi_token,
                })),
                TraitItem::Macro(_) => None,
                TraitItem::Verbatim(_) => None,
            })
            .collect(),
        Item::TraitAlias(_) => Vec::new(),
        Item::Impl(_) => Vec::new(),
        Item::Macro(_) => Vec::new(),
        Item::Macro2(_) => Vec::new(),
        Item::Verbatim(_) => Vec::new(),
    }
}

fn name_of_item(item: &Item) -> Option<&Ident> {
    match item {
        Item::ExternCrate(item) => match &item.rename {
            Some((_, rename)) => Some(rename),
            None => Some(&item.ident),
        },
        Item::Use(_) => None,
        Item::Static(item) => Some(&item.ident),
        Item::Const(item) => Some(&item.ident),
        Item::Fn(item) => Some(&item.ident),
        Item::Mod(item) => Some(&item.ident),
        Item::ForeignMod(_) => None,
        Item::Type(item) => Some(&item.ident),
        Item::Existential(item) => Some(&item.ident),
        Item::Struct(item) => Some(&item.ident),
        Item::Enum(item) => Some(&item.ident),
        Item::Union(item) => Some(&item.ident),
        Item::Trait(item) => Some(&item.ident),
        Item::TraitAlias(item) => Some(&item.ident),
        Item::Impl(_) => None,
        Item::Macro(item) => item.ident.as_ref(),
        Item::Macro2(item) => Some(&item.ident),
        Item::Verbatim(_) => None,
    }
}
<commit_msg>Better name for the item flat_map function<commit_after>use std::fmt::{self, Display};
use std::mem;
use std::str::FromStr;

use proc_macro2::Span;
use syn::{File, Ident, Item, ItemConst, ItemFn, ItemMod, ItemType, TraitItem, Visibility};

#[derive(Debug)]
pub struct Filter {
    segments: Vec<Ident>,
}

impl FromStr for Filter {
    type Err = String;

    fn from_str(input: &str) -> Result<Self, Self::Err> {
        let mut segments = Vec::new();
        for segment in input.split("::") {
            match syn::parse_str(segment) {
                Ok(ident) => segments.push(ident),
                Err(_) => return Err(format!("`{}` is not an identifier", segment)),
            }
        }
        if segments.is_empty() {
            return Err("empty path".to_owned());
        }
        Ok(Filter { segments })
    }
}

impl Display for Filter {
    fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
        for (i, segment) in self.segments.iter().enumerate() {
            if i > 0 {
                formatter.write_str("::")?;
            }
            Display::fmt(segment, formatter)?;
        }
        Ok(())
    }
}

pub fn filter(syntax_tree: &mut File, filter: &Filter) {
    syntax_tree.shebang = None;
    syntax_tree.attrs.clear();

    let items = mem::replace(&mut syntax_tree.items, Vec::new());
    let root_mod = ItemMod {
        attrs: Vec::new(),
        vis: Visibility::Inherited,
        mod_token: Default::default(),
        ident: Ident::new("root", Span::call_site()),
        content: Some((Default::default(), items)),
        semi: None,
    };
    let mut items = vec![Item::Mod(root_mod)];

    for segment in &filter.segments {
        items = items
            .into_iter()
            .flat_map(contents_of_item)
            .filter(|item| name_of_item(item) == Some(segment))
            .collect();
    }

    if items.len() == 1 {
        items = match items.pop().unwrap() {
            Item::Mod(ItemMod {
                content: Some((_, nested)),
                ..
            }) => nested,
            other => vec![other],
        };
    }

    syntax_tree.items = items;
}

fn contents_of_item(item: Item) -> Vec<Item> {
    match item {
        Item::ExternCrate(_) => Vec::new(),
        Item::Use(_) => Vec::new(),
        Item::Static(_) => Vec::new(),
        Item::Const(_) => Vec::new(),
        Item::Fn(_) => Vec::new(),
        Item::Mod(item_mod) => match item_mod.content {
            Some((_, nested)) => nested,
            None => Vec::new(),
        },
        Item::ForeignMod(_) => Vec::new(),
        Item::Type(_) => Vec::new(),
        Item::Existential(_) => Vec::new(),
        Item::Struct(_) => Vec::new(),
        Item::Enum(_) => Vec::new(),
        Item::Union(_) => Vec::new(),
        Item::Trait(item_trait) => item_trait
            .items
            .into_iter()
            .filter_map(|trait_item| match trait_item {
                TraitItem::Const(item) => Some(Item::Const(ItemConst {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    const_token: item.const_token,
                    ident: item.ident,
                    colon_token: item.colon_token,
                    ty: Box::new(item.ty),
                    eq_token: item.default.as_ref()?.0,
                    expr: Box::new(item.default?.1),
                    semi_token: item.semi_token,
                })),
                TraitItem::Method(item) => Some(Item::Fn(ItemFn {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    constness: item.sig.constness,
                    unsafety: item.sig.unsafety,
                    asyncness: item.sig.asyncness,
                    abi: item.sig.abi,
                    ident: item.sig.ident,
                    decl: Box::new(item.sig.decl),
                    block: Box::new(item.default?),
                })),
                TraitItem::Type(item) => Some(Item::Type(ItemType {
                    attrs: item.attrs,
                    vis: Visibility::Inherited,
                    type_token: item.type_token,
                    ident: item.ident,
                    generics: item.generics,
                    eq_token: item.default.as_ref()?.0,
                    ty: Box::new(item.default?.1),
                    semi_token: item.semi_token,
                })),
                TraitItem::Macro(_) => None,
                TraitItem::Verbatim(_) => None,
            })
            .collect(),
        Item::TraitAlias(_) => Vec::new(),
        Item::Impl(_) => Vec::new(),
        Item::Macro(_) => Vec::new(),
        Item::Macro2(_) => Vec::new(),
        Item::Verbatim(_) => Vec::new(),
    }
}

fn name_of_item(item: &Item) -> Option<&Ident> {
    match item {
        Item::ExternCrate(item) => match &item.rename {
            Some((_, rename)) => Some(rename),
            None => Some(&item.ident),
        },
        Item::Use(_) => None,
        Item::Static(item) => Some(&item.ident),
        Item::Const(item) => Some(&item.ident),
        Item::Fn(item) => Some(&item.ident),
        Item::Mod(item) => Some(&item.ident),
        Item::ForeignMod(_) => None,
        Item::Type(item) => Some(&item.ident),
        Item::Existential(item) => Some(&item.ident),
        Item::Struct(item) => Some(&item.ident),
        Item::Enum(item) => Some(&item.ident),
        Item::Union(item) => Some(&item.ident),
        Item::Trait(item) => Some(&item.ident),
        Item::TraitAlias(item) => Some(&item.ident),
        Item::Impl(_) => None,
        Item::Macro(item) => item.ident.as_ref(),
        Item::Macro2(item) => Some(&item.ident),
        Item::Verbatim(_) => None,
    }
}
<|endoftext|>


<commit_before>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use Groups;
use GroupsListing;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,

    groups: GroupsListing,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, client: {:?}, pagination: {:?} }}",
                self.scheme, self.domain, self.port, self.client, self.pagination)
    }
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
            groups: GroupsListing {},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:443/api/v3/projects?private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("projects"), expected_url);
    /// ```
    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, serde_json::Error>
            where T: serde::Deserialize {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        serde_json::from_str(&body.as_str())
    }

    pub fn version(&self) -> Result<Version, serde_json::Error> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<Groups, serde_json::Error> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<Projects, serde_json::Error> {
        self.get("projects")
    }

    pub fn groups_listing(&mut self) -> GroupsListing {
        GroupsListing { }
    }
}

/*
#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
    }
}
*/
<commit_msg>No need for member GroupsListing<commit_after>
use std::fmt;
use std::io::Read;  // Trait providing read_to_string()
use std::env;

use hyper;
use serde;
use serde_json;

use Version;
use Projects;
use Groups;
use GroupsListing;

pub const API_VERSION: u16 = 3;

#[derive(Debug)]
pub struct Pagination {
    pub page: u16,
    pub per_page: u16,
}

pub struct GitLab {
    scheme: String,
    domain: String,
    port: u16,
    private_token: String,
    client: hyper::Client,
    pagination: Pagination,
}

// Explicitly implement Debug trait for GitLab so we can hide the token.
impl fmt::Debug for GitLab {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        write!(f, "GitLab {{ scheme: {}, domain: {}, port: {}, private_token: XXXXXXXXXXXXXXXXXXXX, client: {:?}, pagination: {:?} }}",
                self.scheme, self.domain, self.port, self.client, self.pagination)
    }
}

impl GitLab {

    pub fn new(scheme: &str, domain: &str, port: u16, private_token: &str) -> GitLab {
        GitLab {
            scheme: scheme.to_string(),
            domain: domain.to_string(),
            port:   port,
            private_token: private_token.to_string(),
            client: match env::var("HTTP_PROXY") {
                Ok(proxy) => {
                    let proxy: Vec<&str> = proxy.trim_left_matches("http://").split(':').collect();
                    let hostname = proxy[0].to_string();
                    let port = proxy[1];

                    hyper::Client::with_http_proxy(hostname, port.parse().unwrap())
                },
                Err(_) => hyper::Client::new(),
            },
            pagination: Pagination {page: 1, per_page: 20},
        }
    }

    pub fn new_http(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("http", &domain, 80, &private_token)
    }

    pub fn new_https(domain: &str, private_token: &str) -> GitLab {
        GitLab::new("https", &domain, 443, &private_token)
    }

    /// Build a URL used to access GitLab instance, including some parameters.
    ///
    /// # Examples
    ///
    /// Example from GitLab: https://docs.gitlab.com/ce/api/#basic-usage
    ///
    /// ```
    /// use gitlab_api::GitLab;
    ///
    /// let expected_url = "https://gitlab.example.com:443/api/v3/projects?private_token=XXXXXXXXXXXXX&page=1&per_page=20";
    ///
    /// let gl = GitLab::new_https("gitlab.example.com", "XXXXXXXXXXXXX");
    ///
    /// assert_eq!(gl.build_url("projects"), expected_url);
    /// ```
    pub fn build_url(&self, command: &str) -> String {
        format!("{}://{}:{}/api/v{}/{}?private_token={}&page={}&per_page={}",
                                self.scheme,
                                self.domain,
                                self.port,
                                API_VERSION,
                                command,
                                self.private_token,
                                self.pagination.page,
                                self.pagination.per_page)
    }

    pub fn attempt_connection(&self) -> Result<hyper::client::Response, hyper::Error> {
        let url = self.build_url("version");
        // Close connections after each GET.
        let res = self.client.get(&url).header(hyper::header::Connection::close()).send();

        res
    }

    pub fn set_pagination(&mut self, pagination: Pagination) {
        self.pagination = pagination;
    }

    pub fn get<T>(&self, command: &str) -> Result<T, serde_json::Error>
            where T: serde::Deserialize {

        let url = self.build_url(command);
        let mut res: hyper::client::Response =
                        self.client
                        .get(&url)
                        .header(hyper::header::Connection::close())
                        .send()
                        .unwrap();

        let mut body = String::new();
        res.read_to_string(&mut body).unwrap();

        serde_json::from_str(&body.as_str())
    }

    pub fn version(&self) -> Result<Version, serde_json::Error> {
        self.get("version")
    }

    pub fn groups(&self) -> Result<Groups, serde_json::Error> {
        self.get("groups")
    }

    pub fn projects(&self) -> Result<Projects, serde_json::Error> {
        self.get("projects")
    }

    pub fn groups_listing(&mut self) -> GroupsListing {
        GroupsListing { }
    }
}

/*
#[cfg(test)]
mod tests {

    #[test]
    fn it_works() {
    }
}
*/
<|endoftext|>


<commit_before>// Non-camel case types are used for Stomp Protocol version enum variants
#![allow(non_camel_case_types)]

use collections::slice::Iter;

// Ideally this would be a simple typedef. However:
// See Rust bug #11047: https://github.com/mozilla/rust/issues/11047
// Cannot call static methods (`with_capacity`) on type aliases (`HeaderList`)
pub struct HeaderList {
  pub headers: Vec<Header>
}

impl HeaderList {
  pub fn new() -> HeaderList {
    HeaderList::with_capacity(0)
  }
  pub fn with_capacity(capacity: usize) -> HeaderList {
    HeaderList {
      headers: Vec::with_capacity(capacity)
    }
  }

  pub fn push(&mut self, header: Header) {
    self.headers.push(header);
  }

  pub fn iter<'a>(&'a self) -> Iter<'a, Header> {
    self.headers.iter()
  }

}

pub struct Header {
  buffer : String,
  delimiter_index : u32
}

impl Header {
  fn from_string(raw_string: &str) -> Option<Header> {
    let delimiter_index = match raw_string.find(':') {
      Some(index) => index,
      None => return None
    };
    let mut header = Header{
      buffer: raw_string.to_string(),
      delimiter_index: delimiter_index as u32
    };
    header = Header::decode_key_value(header.get_key(), header.get_value());
    Some(header)
  }

  pub fn encode_string(raw_string: &str) -> Option<Header> {
    let header = Header::from_string(raw_string);
    header.map(|h| Header::encode_key_value(h.get_key(), h.get_value()))
  }

  pub fn decode_string(raw_string: &str) -> Option<Header> {
    let header = Header::from_string(raw_string);
    header.map(|h| Header::decode_key_value(h.get_key(), h.get_value()))
  }

  pub fn encode_key_value(key: &str, value: &str) -> Header {
    let raw_string = format!("{}:{}", key, Header::encode_value(value));
    Header {
      buffer: raw_string,
      delimiter_index: key.len() as u32
    }
  }

  pub fn decode_key_value(key: &str, value: &str) -> Header {
    let raw_string = format!("{}:{}", key, Header::decode_value(value));
    Header {
      buffer: raw_string,
      delimiter_index: key.len() as u32
    }
  }

  //TODO: Optimize this method.
  fn decode_value(value: &str) -> String {
    value
      .replace(r"\c", ":")
      .replace(r"\n", "\n")
      .replace(r"\r", "\r")
      .replace(r"\\", "\\")
  }

//TODO: Optimize this method.
  fn encode_value(value: &str) -> String {
    value
      .replace("\\", r"\\") // Order is significant
      .replace("\r", r"\r")
      .replace("\n", r"\n")
      .replace(":", r"\c")
  }

  pub fn get_raw<'a>(&'a self) -> &'a str {
    self.buffer.as_slice()
  }

  pub fn get_key<'a>(&'a self) -> &'a str {
    self.buffer.as_slice().slice_to(self.delimiter_index as usize)
  }

  pub fn get_value<'a>(&'a self) -> &'a str {
    self.buffer.as_slice().slice_from(self.delimiter_index as usize + 1)
  }

}

// Headers in the Spec
pub struct AcceptVersion(pub Vec<StompVersion>);
pub struct Ack<'a>(pub &'a str);
#[derive(Copy)]
pub struct ContentLength(pub u32);
pub struct Custom(pub Header);
pub struct Destination<'a> (pub &'a str);
#[derive(Copy)]
pub struct HeartBeat(pub u32, pub u32);
pub struct Host<'a>(pub &'a str);
pub struct Id<'a>(pub &'a str);
pub struct Login<'a>(pub &'a str);
pub struct MessageId<'a>(pub &'a str);
pub struct Passcode<'a>(pub &'a str);
pub struct Receipt<'a>(pub &'a str);
pub struct ReceiptId<'a>(pub &'a str);
pub struct Server<'a>(pub &'a str);
pub struct Session<'a> (pub &'a str);
pub struct Subscription<'a>(pub &'a str);
pub struct Transaction<'a>(pub &'a str);
#[derive(Copy)]
pub struct Version(pub StompVersion);

#[derive(Copy)]
pub enum StompVersion {
  Stomp_v1_0,
  Stomp_v1_1,
  Stomp_v1_2,
}

pub trait StompHeaderSet {
  fn get_content_length(&self) -> Option<ContentLength>;
  fn get_header<'a>(&'a self, key: &str) -> Option<&'a Header>;
  fn get_accept_version<'a>(&'a self) -> Option<Vec<StompVersion>>;
  fn get_ack<'a>(&'a self) -> Option<Ack<'a>>;
  fn get_destination<'a>(&'a self) -> Option<Destination<'a>>;
  fn get_heart_beat(&self) -> Option<HeartBeat>;
  fn get_host<'a>(&'a self) -> Option<Host<'a>>;
  fn get_id<'a>(&'a self) -> Option<Id<'a>>;
  fn get_login<'a>(&'a self) -> Option<Login<'a>>;
  fn get_message_id<'a>(&'a self) -> Option<MessageId<'a>>;
  fn get_passcode<'a>(&'a self) -> Option<Passcode<'a>>;
  fn get_receipt<'a>(&'a self) -> Option<Receipt<'a>>;
  fn get_receipt_id<'a>(&'a self) -> Option<ReceiptId<'a>>;
  fn get_server<'a>(&'a self) -> Option<Server<'a>>;
  fn get_session<'a>(&'a self) -> Option<Session<'a>>;
  fn get_subscription<'a>(&'a self) -> Option<Subscription<'a>>;
  fn get_transaction<'a>(&'a self) -> Option<Transaction<'a>>;
  fn get_version(&self) -> Option<Version>;
}

impl StompHeaderSet for HeaderList {

  fn get_header<'a>(&'a self, key: &str) -> Option<&'a Header>{
    self.headers.iter().find(|header|
      match **header {
        ref h if h.get_key() == key => true,
        _ => false
      }
    )
  }

  fn get_accept_version(&self) -> Option<Vec<StompVersion>> {
    let versions : &str = match self.get_header("accept-version") {
      Some(h) => h.get_value(),
      None => return None
    };
    let versions: Vec<StompVersion> = versions.split(',').filter_map(|v| match v.trim() {
      "1.0" => Some(StompVersion::Stomp_v1_0),
      "1.1" => Some(StompVersion::Stomp_v1_1),
      "1.2" => Some(StompVersion::Stomp_v1_2),
      _ => None
    }).collect();
    Some(versions)
  }

  fn get_ack<'a>(&'a self) -> Option<Ack<'a>> {
    match self.get_header("ack") {
      Some(h) => Some(Ack(h.get_value())),
      None => None
    }
  }

  fn get_destination<'a>(&'a self) -> Option<Destination<'a>> {
    match self.get_header("destination") {
      Some(h) => Some(Destination(h.get_value())),
      None => return None
    }
  }

  fn get_heart_beat(&self) -> Option<HeartBeat> {
    let spec = match self.get_header("heart-beat") {
      Some(h) => h.get_value(),
      None => return None
    };
    let spec_list: Vec<u32> = spec.split(',').filter_map(|str_val| str_val.parse::<u32>()).collect();
    match spec_list.as_slice() {
      [x, y] => Some(HeartBeat(x, y)),
      _ => None
    }
  }

  fn get_host<'a>(&'a self) -> Option<Host<'a>> {
    match self.get_header("host") {
      Some(h) => Some(Host(h.get_value())),
      None => None
    }
  }

  fn get_id<'a>(&'a self) -> Option<Id<'a>> {
    match self.get_header("id") {
      Some(h) => Some(Id(h.get_value())),
      None => None
    }
  }

  fn get_login<'a>(&'a self) -> Option<Login<'a>> {
    match self.get_header("login"){
      Some(h) => Some(Login(h.get_value())),
      None => None
    }
  }

  fn get_message_id<'a>(&'a self) -> Option<MessageId<'a>> {
    match self.get_header("message-id"){
      Some(h) => Some(MessageId(h.get_value())),
      None => None
    }
  }

  fn get_passcode<'a>(&'a self) -> Option<Passcode<'a>> {
    match self.get_header("passcode"){
      Some(h) => Some(Passcode(h.get_value())),
      None => None
    }
  }

  fn get_receipt<'a>(&'a self) -> Option<Receipt<'a>> {
    match self.get_header("receipt"){
      Some(h) => Some(Receipt(h.get_value())),
      None => None
    }
  }

  fn get_receipt_id<'a>(&'a self) -> Option<ReceiptId<'a>> {
    match self.get_header("receipt-id"){
      Some(h) => Some(ReceiptId(h.get_value())),
      None => None
    }
  }

  fn get_server<'a>(&'a self) -> Option<Server<'a>> {
    match self.get_header("server"){
      Some(h) => Some(Server(h.get_value())),
      None => None
    }
  }

  fn get_session<'a>(&'a self) -> Option<Session<'a>> {
    match self.get_header("session"){
      Some(h) => Some(Session(h.get_value())),
      None => None
    }
  }

  fn get_subscription<'a>(&'a self) -> Option<Subscription<'a>> {
    match self.get_header("subscription"){
      Some(h) => Some(Subscription(h.get_value())),
      None => None
    }
  }

  fn get_transaction<'a>(&'a self) -> Option<Transaction<'a>> {
    match self.get_header("transaction"){
      Some(h) => Some(Transaction(h.get_value())),
      None => None
    }
  }

  fn get_version(&self) -> Option<Version> {
    let version = match self.get_header("version"){
      Some(h) => h.get_value(),
      None => return None
    };
    match (version).as_slice() {
      "1.0" => Some(Version(StompVersion::Stomp_v1_0)), // TODO: Impl FromStr for StompVersion
      "1.1" => Some(Version(StompVersion::Stomp_v1_1)),
      "1.2" => Some(Version(StompVersion::Stomp_v1_2)),
      _ => None
    }
  }

  fn get_content_length(&self) -> Option<ContentLength> {
    let length = match self.get_header("content-length") {
      Some(h) => h.get_value(),
      None => return None
    };
    match length.parse::<u32>() {
      Some(l) => Some(ContentLength(l)),
      None => None
    }
  }

}

#[macro_export]
macro_rules! header_list [

  ($($header: expr), *) => ({
    let mut header_list = HeaderList::new();

    $(header_list.push($header);)*

    header_list
  })

];
<commit_msg>Removed some extra whitespace.<commit_after>// Non-camel case types are used for Stomp Protocol version enum variants
#![allow(non_camel_case_types)]

use collections::slice::Iter;

// Ideally this would be a simple typedef. However:
// See Rust bug #11047: https://github.com/mozilla/rust/issues/11047
// Cannot call static methods (`with_capacity`) on type aliases (`HeaderList`)
pub struct HeaderList {
  pub headers: Vec<Header>
}

impl HeaderList {
  pub fn new() -> HeaderList {
    HeaderList::with_capacity(0)
  }
  pub fn with_capacity(capacity: usize) -> HeaderList {
    HeaderList {
      headers: Vec::with_capacity(capacity)
    }
  }

  pub fn push(&mut self, header: Header) {
    self.headers.push(header);
  }

  pub fn iter<'a>(&'a self) -> Iter<'a, Header> {
    self.headers.iter()
  }

}

pub struct Header {
  buffer : String,
  delimiter_index : u32
}

impl Header {
  fn from_string(raw_string: &str) -> Option<Header> {
    let delimiter_index = match raw_string.find(':') {
      Some(index) => index,
      None => return None
    };
    let mut header = Header{
      buffer: raw_string.to_string(),
      delimiter_index: delimiter_index as u32
    };
    header = Header::decode_key_value(header.get_key(), header.get_value());
    Some(header)
  }

  pub fn encode_string(raw_string: &str) -> Option<Header> {
    let header = Header::from_string(raw_string);
    header.map(|h| Header::encode_key_value(h.get_key(), h.get_value()))
  }

  pub fn decode_string(raw_string: &str) -> Option<Header> {
    let header = Header::from_string(raw_string);
    header.map(|h| Header::decode_key_value(h.get_key(), h.get_value()))
  }

  pub fn encode_key_value(key: &str, value: &str) -> Header {
    let raw_string = format!("{}:{}", key, Header::encode_value(value));
    Header {
      buffer: raw_string,
      delimiter_index: key.len() as u32
    }
  }

  pub fn decode_key_value(key: &str, value: &str) -> Header {
    let raw_string = format!("{}:{}", key, Header::decode_value(value));
    Header {
      buffer: raw_string,
      delimiter_index: key.len() as u32
    }
  }

  //TODO: Optimize this method.
  fn decode_value(value: &str) -> String {
    value
      .replace(r"\c", ":")
      .replace(r"\n", "\n")
      .replace(r"\r", "\r")
      .replace(r"\\", "\\")
  }

//TODO: Optimize this method.
  fn encode_value(value: &str) -> String {
    value
      .replace("\\", r"\\") // Order is significant
      .replace("\r", r"\r")
      .replace("\n", r"\n")
      .replace(":", r"\c")
  }

  pub fn get_raw<'a>(&'a self) -> &'a str {
    self.buffer.as_slice()
  }

  pub fn get_key<'a>(&'a self) -> &'a str {
    self.buffer.as_slice().slice_to(self.delimiter_index as usize)
  }

  pub fn get_value<'a>(&'a self) -> &'a str {
    self.buffer.as_slice().slice_from(self.delimiter_index as usize + 1)
  }

}

// Headers in the Spec
pub struct AcceptVersion(pub Vec<StompVersion>);
pub struct Ack<'a>(pub &'a str);
#[derive(Copy)]
pub struct ContentLength(pub u32);
pub struct Custom(pub Header);
pub struct Destination<'a> (pub &'a str);
#[derive(Copy)]
pub struct HeartBeat(pub u32, pub u32);
pub struct Host<'a>(pub &'a str);
pub struct Id<'a>(pub &'a str);
pub struct Login<'a>(pub &'a str);
pub struct MessageId<'a>(pub &'a str);
pub struct Passcode<'a>(pub &'a str);
pub struct Receipt<'a>(pub &'a str);
pub struct ReceiptId<'a>(pub &'a str);
pub struct Server<'a>(pub &'a str);
pub struct Session<'a> (pub &'a str);
pub struct Subscription<'a>(pub &'a str);
pub struct Transaction<'a>(pub &'a str);
#[derive(Copy)]
pub struct Version(pub StompVersion);

#[derive(Copy)]
pub enum StompVersion {
  Stomp_v1_0,
  Stomp_v1_1,
  Stomp_v1_2,
}

pub trait StompHeaderSet {
  fn get_content_length(&self) -> Option<ContentLength>;
  fn get_header<'a>(&'a self, key: &str) -> Option<&'a Header>;
  fn get_accept_version<'a>(&'a self) -> Option<Vec<StompVersion>>;
  fn get_ack<'a>(&'a self) -> Option<Ack<'a>>;
  fn get_destination<'a>(&'a self) -> Option<Destination<'a>>;
  fn get_heart_beat(&self) -> Option<HeartBeat>;
  fn get_host<'a>(&'a self) -> Option<Host<'a>>;
  fn get_id<'a>(&'a self) -> Option<Id<'a>>;
  fn get_login<'a>(&'a self) -> Option<Login<'a>>;
  fn get_message_id<'a>(&'a self) -> Option<MessageId<'a>>;
  fn get_passcode<'a>(&'a self) -> Option<Passcode<'a>>;
  fn get_receipt<'a>(&'a self) -> Option<Receipt<'a>>;
  fn get_receipt_id<'a>(&'a self) -> Option<ReceiptId<'a>>;
  fn get_server<'a>(&'a self) -> Option<Server<'a>>;
  fn get_session<'a>(&'a self) -> Option<Session<'a>>;
  fn get_subscription<'a>(&'a self) -> Option<Subscription<'a>>;
  fn get_transaction<'a>(&'a self) -> Option<Transaction<'a>>;
  fn get_version(&self) -> Option<Version>;
}

impl StompHeaderSet for HeaderList {

  fn get_header<'a>(&'a self, key: &str) -> Option<&'a Header>{
    self.headers.iter().find(|header|
      match **header {
        ref h if h.get_key() == key => true,
        _ => false
      }
    )
  }

  fn get_accept_version(&self) -> Option<Vec<StompVersion>> {
    let versions : &str = match self.get_header("accept-version") {
      Some(h) => h.get_value(),
      None => return None
    };
    let versions: Vec<StompVersion> = versions.split(',').filter_map(|v| match v.trim() {
      "1.0" => Some(StompVersion::Stomp_v1_0),
      "1.1" => Some(StompVersion::Stomp_v1_1),
      "1.2" => Some(StompVersion::Stomp_v1_2),
      _ => None
    }).collect();
    Some(versions)
  }

  fn get_ack<'a>(&'a self) -> Option<Ack<'a>> {
    match self.get_header("ack") {
      Some(h) => Some(Ack(h.get_value())),
      None => None
    }
  }

  fn get_destination<'a>(&'a self) -> Option<Destination<'a>> {
    match self.get_header("destination") {
      Some(h) => Some(Destination(h.get_value())),
      None => return None
    }
  }

  fn get_heart_beat(&self) -> Option<HeartBeat> {
    let spec = match self.get_header("heart-beat") {
      Some(h) => h.get_value(),
      None => return None
    };
    let spec_list: Vec<u32> = spec.split(',').filter_map(|str_val| str_val.parse::<u32>()).collect();
    match spec_list.as_slice() {
      [x, y] => Some(HeartBeat(x, y)),
      _ => None
    }
  }

  fn get_host<'a>(&'a self) -> Option<Host<'a>> {
    match self.get_header("host") {
      Some(h) => Some(Host(h.get_value())),
      None => None
    }
  }

  fn get_id<'a>(&'a self) -> Option<Id<'a>> {
    match self.get_header("id") {
      Some(h) => Some(Id(h.get_value())),
      None => None
    }
  }

  fn get_login<'a>(&'a self) -> Option<Login<'a>> {
    match self.get_header("login"){
      Some(h) => Some(Login(h.get_value())),
      None => None
    }
  }

  fn get_message_id<'a>(&'a self) -> Option<MessageId<'a>> {
    match self.get_header("message-id"){
      Some(h) => Some(MessageId(h.get_value())),
      None => None
    }
  }

  fn get_passcode<'a>(&'a self) -> Option<Passcode<'a>> {
    match self.get_header("passcode"){
      Some(h) => Some(Passcode(h.get_value())),
      None => None
    }
  }

  fn get_receipt<'a>(&'a self) -> Option<Receipt<'a>> {
    match self.get_header("receipt"){
      Some(h) => Some(Receipt(h.get_value())),
      None => None
    }
  }

  fn get_receipt_id<'a>(&'a self) -> Option<ReceiptId<'a>> {
    match self.get_header("receipt-id"){
      Some(h) => Some(ReceiptId(h.get_value())),
      None => None
    }
  }

  fn get_server<'a>(&'a self) -> Option<Server<'a>> {
    match self.get_header("server"){
      Some(h) => Some(Server(h.get_value())),
      None => None
    }
  }

  fn get_session<'a>(&'a self) -> Option<Session<'a>> {
    match self.get_header("session"){
      Some(h) => Some(Session(h.get_value())),
      None => None
    }
  }

  fn get_subscription<'a>(&'a self) -> Option<Subscription<'a>> {
    match self.get_header("subscription"){
      Some(h) => Some(Subscription(h.get_value())),
      None => None
    }
  }

  fn get_transaction<'a>(&'a self) -> Option<Transaction<'a>> {
    match self.get_header("transaction"){
      Some(h) => Some(Transaction(h.get_value())),
      None => None
    }
  }

  fn get_version(&self) -> Option<Version> {
    let version = match self.get_header("version"){
      Some(h) => h.get_value(),
      None => return None
    };
    match (version).as_slice() {
      "1.0" => Some(Version(StompVersion::Stomp_v1_0)), // TODO: Impl FromStr for StompVersion
      "1.1" => Some(Version(StompVersion::Stomp_v1_1)),
      "1.2" => Some(Version(StompVersion::Stomp_v1_2)),
      _ => None
    }
  }

  fn get_content_length(&self) -> Option<ContentLength> {
    let length = match self.get_header("content-length") {
      Some(h) => h.get_value(),
      None => return None
    };
    match length.parse::<u32>() {
      Some(l) => Some(ContentLength(l)),
      None => None
    }
  }

}

#[macro_export]
macro_rules! header_list [
  ($($header: expr), *) => ({
    let mut header_list = HeaderList::new();
    $(header_list.push($header);)*
    header_list
  })
];
<|endoftext|>