<commit_before>#[cfg(feature = "tonic")]
use crate::proto::resource::v1::Resource;

#[cfg(feature = "tonic")]
use crate::proto::trace::v1::{
    span, status, InstrumentationLibrarySpans, ResourceSpans, Span, Status,
};

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use crate::proto::grpcio::resource::Resource;

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use crate::proto::grpcio::trace::{
    InstrumentationLibrarySpans, ResourceSpans, Span, Span_Event, Span_Link, Span_SpanKind, Status,
    Status_StatusCode,
};

use crate::transform::common::{to_nanos, Attributes};
use opentelemetry::sdk::export::trace::SpanData;
use opentelemetry::trace::{Link, SpanKind, StatusCode};

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use protobuf::reflect::ProtobufValue;

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use protobuf::{RepeatedField, SingularPtrField};

#[cfg(feature = "tonic")]
impl From<SpanKind> for span::SpanKind {
    fn from(span_kind: SpanKind) -> Self {
        match span_kind {
            SpanKind::Client => span::SpanKind::Client,
            SpanKind::Consumer => span::SpanKind::Consumer,
            SpanKind::Internal => span::SpanKind::Internal,
            SpanKind::Producer => span::SpanKind::Producer,
            SpanKind::Server => span::SpanKind::Server,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<SpanKind> for Span_SpanKind {
    fn from(span_kind: SpanKind) -> Self {
        match span_kind {
            SpanKind::Client => Span_SpanKind::SPAN_KIND_CLIENT,
            SpanKind::Consumer => Span_SpanKind::SPAN_KIND_CONSUMER,
            SpanKind::Internal => Span_SpanKind::SPAN_KIND_INTERNAL,
            SpanKind::Producer => Span_SpanKind::SPAN_KIND_PRODUCER,
            SpanKind::Server => Span_SpanKind::SPAN_KIND_SERVER,
        }
    }
}

#[cfg(feature = "tonic")]
impl From<StatusCode> for status::StatusCode {
    fn from(status_code: StatusCode) -> Self {
        match status_code {
            StatusCode::Ok => status::StatusCode::Ok,
            StatusCode::Unset => status::StatusCode::Unset,
            StatusCode::Error => status::StatusCode::Error,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<StatusCode> for Status_StatusCode {
    fn from(status_code: StatusCode) -> Self {
        match status_code {
            StatusCode::Ok => Status_StatusCode::STATUS_CODE_OK,
            StatusCode::Unset => Status_StatusCode::STATUS_CODE_UNSET,
            StatusCode::Error => Status_StatusCode::STATUS_CODE_ERROR,
        }
    }
}

#[cfg(feature = "tonic")]
impl From<Link> for span::Link {
    fn from(link: Link) -> Self {
        span::Link {
            trace_id: link
                .span_context()
                .trace_id()
                .to_u128()
                .to_be_bytes()
                .to_vec(),
            span_id: link
                .span_context()
                .span_id()
                .to_u64()
                .to_be_bytes()
                .to_vec(),
            trace_state: link.span_context().trace_state().header(),
            attributes: Attributes::from(link.attributes().clone()).0,
            dropped_attributes_count: 0,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<Link> for Span_Link {
    fn from(link: Link) -> Self {
        Span_Link {
            trace_id: link
                .span_context()
                .trace_id()
                .to_u128()
                .to_be_bytes()
                .to_vec(),
            span_id: link
                .span_context()
                .span_id()
                .to_u64()
                .to_be_bytes()
                .to_vec(),
            trace_state: link.span_context().trace_state().header(),
            attributes: Attributes::from(link.attributes().clone()).0,
            dropped_attributes_count: 0,
            ..Default::default()
        }
    }
}

impl From<SpanData> for ResourceSpans {
    #[cfg(feature = "tonic")]
    fn from(source_span: SpanData) -> Self {
        let span_kind: span::SpanKind = source_span.span_kind.into();
        ResourceSpans {
            resource: Some(Resource {
                attributes: Default::default(),
                dropped_attributes_count: 0,
            }),
            instrumentation_library_spans: vec![InstrumentationLibrarySpans {
                instrumentation_library: Default::default(),
                spans: vec![Span {
                    trace_id: source_span
                        .span_context
                        .trace_id()
                        .to_u128()
                        .to_be_bytes()
                        .to_vec(),
                    span_id: source_span
                        .span_context
                        .span_id()
                        .to_u64()
                        .to_be_bytes()
                        .to_vec(),
                    trace_state: source_span.span_context.trace_state().header(),
                    parent_span_id: {
                        if source_span.parent_span_id.to_u64() > 0 {
                            source_span.parent_span_id.to_u64().to_be_bytes().to_vec()
                        } else {
                            vec![]
                        }
                    },
                    name: source_span.name,
                    kind: span_kind as i32,
                    start_time_unix_nano: to_nanos(source_span.start_time),
                    end_time_unix_nano: to_nanos(source_span.end_time),
                    dropped_attributes_count: source_span.attributes.dropped_count(),
                    attributes: Attributes::from(source_span.attributes).0,
                    dropped_events_count: source_span.message_events.dropped_count(),
                    events: source_span
                        .message_events
                        .into_iter()
                        .map(|event| span::Event {
                            time_unix_nano: to_nanos(event.timestamp),
                            name: event.name,
                            attributes: Attributes::from(event.attributes).0,
                            dropped_attributes_count: 0,
                        })
                        .collect(),
                    dropped_links_count: source_span.links.dropped_count(),
                    links: source_span.links.into_iter().map(Into::into).collect(),
                    status: Some(Status {
                        code: status::StatusCode::from(source_span.status_code).into(),
                        message: source_span.status_message,
                        ..Default::default()
                    }),
                }],
            }],
        }
    }

    #[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
    fn from(source_span: SpanData) -> Self {
        let resource_attributes: Attributes = source_span
            .resource
            .iter()
            .map(|(k, v)| opentelemetry::KeyValue::new(k.clone(), v.clone()))
            .collect::<Vec<_>>()
            .into();
        ResourceSpans {
            resource: SingularPtrField::from(Some(Resource {
                attributes: resource_attributes.0,
                dropped_attributes_count: 0,
                ..Default::default()
            })),
            instrumentation_library_spans: RepeatedField::from_vec(vec![
                InstrumentationLibrarySpans {
                    instrumentation_library: Default::default(),
                    spans: RepeatedField::from_vec(vec![Span {
                        trace_id: source_span
                            .span_context
                            .trace_id()
                            .to_u128()
                            .to_be_bytes()
                            .to_vec(),
                        span_id: source_span
                            .span_context
                            .span_id()
                            .to_u64()
                            .to_be_bytes()
                            .to_vec(),
                        trace_state: source_span.span_context.trace_state().header(),
                        parent_span_id: {
                            if source_span.parent_span_id.to_u64().is_non_zero() {
                                source_span.parent_span_id.to_u64().to_be_bytes().to_vec()
                            } else {
                                vec![]
                            }
                        },
                        name: source_span.name,
                        kind: source_span.span_kind.into(),
                        start_time_unix_nano: to_nanos(source_span.start_time),
                        end_time_unix_nano: to_nanos(source_span.end_time),
                        dropped_attributes_count: source_span.attributes.dropped_count(),
                        attributes: Attributes::from(source_span.attributes).0,
                        dropped_events_count: source_span.message_events.dropped_count(),
                        events: RepeatedField::from_vec(
                            source_span
                                .message_events
                                .into_iter()
                                .map(|event| Span_Event {
                                    time_unix_nano: to_nanos(event.timestamp),
                                    name: event.name,
                                    attributes: Attributes::from(event.attributes).0,
                                    dropped_attributes_count: 0,
                                    ..Default::default()
                                })
                                .collect(),
                        ),
                        dropped_links_count: source_span.links.dropped_count(),
                        links: RepeatedField::from_vec(
                            source_span.links.into_iter().map(Into::into).collect(),
                        ),
                        status: SingularPtrField::some(Status {
                            code: Status_StatusCode::from(source_span.status_code),
                            message: source_span.status_message,
                            ..Default::default()
                        }),
                        ..Default::default()
                    }]),
                    ..Default::default()
                },
            ]),
            ..Default::default()
        }
    }
}
<commit_msg>Propagate Resource from Span to proto (Tonic) (#386) (#390)<commit_after>#[cfg(feature = "tonic")]
use crate::proto::resource::v1::Resource;

#[cfg(feature = "tonic")]
use crate::proto::trace::v1::{
    span, status, InstrumentationLibrarySpans, ResourceSpans, Span, Status,
};

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use crate::proto::grpcio::resource::Resource;

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use crate::proto::grpcio::trace::{
    InstrumentationLibrarySpans, ResourceSpans, Span, Span_Event, Span_Link, Span_SpanKind, Status,
    Status_StatusCode,
};

use crate::transform::common::{to_nanos, Attributes};
use opentelemetry::sdk::{export::trace::SpanData, self};
use opentelemetry::trace::{Link, SpanKind, StatusCode};

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use protobuf::reflect::ProtobufValue;

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
use protobuf::{RepeatedField, SingularPtrField};

#[cfg(feature = "tonic")]
impl From<SpanKind> for span::SpanKind {
    fn from(span_kind: SpanKind) -> Self {
        match span_kind {
            SpanKind::Client => span::SpanKind::Client,
            SpanKind::Consumer => span::SpanKind::Consumer,
            SpanKind::Internal => span::SpanKind::Internal,
            SpanKind::Producer => span::SpanKind::Producer,
            SpanKind::Server => span::SpanKind::Server,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<SpanKind> for Span_SpanKind {
    fn from(span_kind: SpanKind) -> Self {
        match span_kind {
            SpanKind::Client => Span_SpanKind::SPAN_KIND_CLIENT,
            SpanKind::Consumer => Span_SpanKind::SPAN_KIND_CONSUMER,
            SpanKind::Internal => Span_SpanKind::SPAN_KIND_INTERNAL,
            SpanKind::Producer => Span_SpanKind::SPAN_KIND_PRODUCER,
            SpanKind::Server => Span_SpanKind::SPAN_KIND_SERVER,
        }
    }
}

#[cfg(feature = "tonic")]
impl From<StatusCode> for status::StatusCode {
    fn from(status_code: StatusCode) -> Self {
        match status_code {
            StatusCode::Ok => status::StatusCode::Ok,
            StatusCode::Unset => status::StatusCode::Unset,
            StatusCode::Error => status::StatusCode::Error,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<StatusCode> for Status_StatusCode {
    fn from(status_code: StatusCode) -> Self {
        match status_code {
            StatusCode::Ok => Status_StatusCode::STATUS_CODE_OK,
            StatusCode::Unset => Status_StatusCode::STATUS_CODE_UNSET,
            StatusCode::Error => Status_StatusCode::STATUS_CODE_ERROR,
        }
    }
}

#[cfg(feature = "tonic")]
impl From<Link> for span::Link {
    fn from(link: Link) -> Self {
        span::Link {
            trace_id: link
                .span_context()
                .trace_id()
                .to_u128()
                .to_be_bytes()
                .to_vec(),
            span_id: link
                .span_context()
                .span_id()
                .to_u64()
                .to_be_bytes()
                .to_vec(),
            trace_state: link.span_context().trace_state().header(),
            attributes: Attributes::from(link.attributes().clone()).0,
            dropped_attributes_count: 0,
        }
    }
}

#[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
impl From<Link> for Span_Link {
    fn from(link: Link) -> Self {
        Span_Link {
            trace_id: link
                .span_context()
                .trace_id()
                .to_u128()
                .to_be_bytes()
                .to_vec(),
            span_id: link
                .span_context()
                .span_id()
                .to_u64()
                .to_be_bytes()
                .to_vec(),
            trace_state: link.span_context().trace_state().header(),
            attributes: Attributes::from(link.attributes().clone()).0,
            dropped_attributes_count: 0,
            ..Default::default()
        }
    }
}

fn resource_attributes(resource: &sdk::Resource) -> Attributes {
    resource
        .iter()
        .map(|(k, v)| opentelemetry::KeyValue::new(k.clone(), v.clone()))
        .collect::<Vec<_>>()
        .into()
}

impl From<SpanData> for ResourceSpans {
    #[cfg(feature = "tonic")]
    fn from(source_span: SpanData) -> Self {
        let span_kind: span::SpanKind = source_span.span_kind.into();
        ResourceSpans {
            resource: Some(Resource {
                attributes: resource_attributes(&source_span.resource).0,
                dropped_attributes_count: 0,
            }),
            instrumentation_library_spans: vec![InstrumentationLibrarySpans {
                instrumentation_library: Default::default(),
                spans: vec![Span {
                    trace_id: source_span
                        .span_context
                        .trace_id()
                        .to_u128()
                        .to_be_bytes()
                        .to_vec(),
                    span_id: source_span
                        .span_context
                        .span_id()
                        .to_u64()
                        .to_be_bytes()
                        .to_vec(),
                    trace_state: source_span.span_context.trace_state().header(),
                    parent_span_id: {
                        if source_span.parent_span_id.to_u64() > 0 {
                            source_span.parent_span_id.to_u64().to_be_bytes().to_vec()
                        } else {
                            vec![]
                        }
                    },
                    name: source_span.name,
                    kind: span_kind as i32,
                    start_time_unix_nano: to_nanos(source_span.start_time),
                    end_time_unix_nano: to_nanos(source_span.end_time),
                    dropped_attributes_count: source_span.attributes.dropped_count(),
                    attributes: Attributes::from(source_span.attributes).0,
                    dropped_events_count: source_span.message_events.dropped_count(),
                    events: source_span
                        .message_events
                        .into_iter()
                        .map(|event| span::Event {
                            time_unix_nano: to_nanos(event.timestamp),
                            name: event.name,
                            attributes: Attributes::from(event.attributes).0,
                            dropped_attributes_count: 0,
                        })
                        .collect(),
                    dropped_links_count: source_span.links.dropped_count(),
                    links: source_span.links.into_iter().map(Into::into).collect(),
                    status: Some(Status {
                        code: status::StatusCode::from(source_span.status_code).into(),
                        message: source_span.status_message,
                        ..Default::default()
                    }),
                }],
            }],
        }
    }

    #[cfg(all(feature = "grpc-sys", not(feature = "tonic")))]
    fn from(source_span: SpanData) -> Self {
        ResourceSpans {
            resource: SingularPtrField::from(Some(Resource {
                attributes: resource_attributes(&source_span.resource).0,
                dropped_attributes_count: 0,
                ..Default::default()
            })),
            instrumentation_library_spans: RepeatedField::from_vec(vec![
                InstrumentationLibrarySpans {
                    instrumentation_library: Default::default(),
                    spans: RepeatedField::from_vec(vec![Span {
                        trace_id: source_span
                            .span_context
                            .trace_id()
                            .to_u128()
                            .to_be_bytes()
                            .to_vec(),
                        span_id: source_span
                            .span_context
                            .span_id()
                            .to_u64()
                            .to_be_bytes()
                            .to_vec(),
                        trace_state: source_span.span_context.trace_state().header(),
                        parent_span_id: {
                            if source_span.parent_span_id.to_u64().is_non_zero() {
                                source_span.parent_span_id.to_u64().to_be_bytes().to_vec()
                            } else {
                                vec![]
                            }
                        },
                        name: source_span.name,
                        kind: source_span.span_kind.into(),
                        start_time_unix_nano: to_nanos(source_span.start_time),
                        end_time_unix_nano: to_nanos(source_span.end_time),
                        dropped_attributes_count: source_span.attributes.dropped_count(),
                        attributes: Attributes::from(source_span.attributes).0,
                        dropped_events_count: source_span.message_events.dropped_count(),
                        events: RepeatedField::from_vec(
                            source_span
                                .message_events
                                .into_iter()
                                .map(|event| Span_Event {
                                    time_unix_nano: to_nanos(event.timestamp),
                                    name: event.name,
                                    attributes: Attributes::from(event.attributes).0,
                                    dropped_attributes_count: 0,
                                    ..Default::default()
                                })
                                .collect(),
                        ),
                        dropped_links_count: source_span.links.dropped_count(),
                        links: RepeatedField::from_vec(
                            source_span.links.into_iter().map(Into::into).collect(),
                        ),
                        status: SingularPtrField::some(Status {
                            code: Status_StatusCode::from(source_span.status_code),
                            message: source_span.status_message,
                            ..Default::default()
                        }),
                        ..Default::default()
                    }]),
                    ..Default::default()
                },
            ]),
            ..Default::default()
        }
    }
}
<|endoftext|>


<commit_before>// This package handles RPC message data encoding/decoding.
// Every RPC message data contains two parts: header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes)| 0x01 (version 2 bytes)| msg_len (4 bytes) | msg_id (8 bytes)|, all use bigendian.
// Now the version is always 1.
// Payload can be any arbitrary data, but we use Protobuf in our problem default.
use std::{result, io, fmt};
use std::error;
use std::convert;
use std::vec::Vec;
use std::io::Write;

use byteorder::{ByteOrder, BigEndian};
use protobuf;

pub const MSG_HEADER_LEN: usize = 16;
pub const MSG_MAGIC: u16 = 0xdaf4;
pub const MSG_VERSION_V1: u16 = 1;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Protobuf(protobuf::ProtobufError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => fmt::Debug::fmt(e, f),
            &Error::Protobuf(ref e) => fmt::Debug::fmt(e, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &Error::Io(ref e) => e.description(),
            &Error::Protobuf(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Protobuf(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<protobuf::ProtobufError> for Error {
    fn from(err: protobuf::ProtobufError) -> Error {
        Error::Protobuf(err)
    }
}

fn other_err(msg: String) -> Error {
    let err = io::Error::new(io::ErrorKind::Other, msg);
    convert::From::from(err)
}

pub type Result<T> = result::Result<T, Error>;

// Encodes message with message ID and protobuf body.
pub fn encode_msg<T: io::Write, M: protobuf::Message>(w: &mut T,
                                                      msg_id: u64,
                                                      msg: &M)
                                                      -> Result<()> {
    let payload_len = msg.compute_size();
    let header = encode_msg_header(msg_id, payload_len as usize);
    try!(w.write(&header));
    try!(msg.write_to_writer(w));

    Ok(())
}

// Decodes encode message, returns message ID.
pub fn decode_msg<T: io::Read, M: protobuf::Message>(r: &mut T, m: &mut M) -> Result<u64> {
    let (message_id, payload) = try!(decode_data(r));
    try!(m.merge_from_bytes(&payload));

    Ok(message_id)
}

// Encodes data with message ID and any arbitrary body.
pub fn encode_data<T: io::Write>(w: &mut T, msg_id: u64, data: &[u8]) -> Result<()> {
    let header = encode_msg_header(msg_id, data.len());

    try!(w.write(&header));
    try!(w.write(data));

    Ok(())
}

// Decodes encoded data, returns message ID.
pub fn decode_data<T: io::Read>(r: &mut T) -> Result<(u64, Vec<u8>)> {
    let mut header = vec![0;MSG_HEADER_LEN];
    try!(r.read_exact(&mut header));

    let (msg_id, payload_len) = try!(decode_msg_header(&mut header));
    let mut payload = vec![0;payload_len];
    try!(r.read_exact(&mut payload));

    Ok((msg_id, payload))
}

// Encode msg header to a 16 bytes header buffer.
pub fn encode_msg_header(msg_id: u64, payload_len: usize) -> Vec<u8> {
    let mut buf = vec![0;MSG_HEADER_LEN];

    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u32(&mut buf[4..8], payload_len as u32);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    return buf;
}

// Decode msg header in header buffer, the buffer length must be equal MSG_HEADER_LEN;
pub fn decode_msg_header(header: &[u8]) -> Result<(u64, usize)> {
    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(other_err(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(other_err(format!("unsupported version {}, we need {} now",
                                     version,
                                     MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let message_id = BigEndian::read_u64(&header[8..16]);

    Ok((message_id, payload_len))
}

#[cfg(test)]
mod tests {
    use bytes::ByteBuf;
    use std::io::Cursor;

    use super::*;
    use proto::raftpb::{Message, MessageType};

    #[test]
    fn test_pbmsg_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_msg(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_msg(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }

    #[test]
    fn test_data_codec() {
        let body = vec![10;10];
        let mut m1 = vec![];
        encode_data(&mut m1, 1, &body).unwrap();

        let mut r = Cursor::new(m1.clone());
        let (msg_id, data) = decode_data(&mut r).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(&data, &body);
    }

    #[test]
    fn test_header_codec() {
        let m1 = encode_msg_header(1, 1);
        let (msg_id, payload_len) = decode_msg_header(&m1).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(payload_len, 1);
    }
}
<commit_msg>codec: Address comment.<commit_after>// This package handles RPC message data encoding/decoding.
// Every RPC message data contains two parts: header + payload.
// Header is 16 bytes, format:
//  | 0xdaf4 (2 bytes magic value) | 0x01 (version 2 bytes) | msg_len (4 bytes) | msg_id (8 bytes) |,
// all use bigendian.
// Now the version is always 1.
// Payload can be any arbitrary data, but we use Protobuf in our program default.
use std::{result, io, fmt};
use std::error;
use std::convert;
use std::vec::Vec;
use std::io::Write;

use byteorder::{ByteOrder, BigEndian};
use protobuf;

pub const MSG_HEADER_LEN: usize = 16;
pub const MSG_MAGIC: u16 = 0xdaf4;
pub const MSG_VERSION_V1: u16 = 1;

#[derive(Debug)]
pub enum Error {
    Io(io::Error),
    Protobuf(protobuf::ProtobufError),
}

impl fmt::Display for Error {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &Error::Io(ref e) => fmt::Debug::fmt(e, f),
            &Error::Protobuf(ref e) => fmt::Debug::fmt(e, f),
        }
    }
}

impl error::Error for Error {
    fn description(&self) -> &str {
        match self {
            // not sure that cause should be included in message
            &Error::Io(ref e) => e.description(),
            &Error::Protobuf(ref e) => e.description(),
        }
    }

    fn cause(&self) -> Option<&error::Error> {
        match self {
            &Error::Io(ref e) => Some(e),
            &Error::Protobuf(ref e) => Some(e),
        }
    }
}

impl From<io::Error> for Error {
    fn from(err: io::Error) -> Error {
        Error::Io(err)
    }
}

impl From<protobuf::ProtobufError> for Error {
    fn from(err: protobuf::ProtobufError) -> Error {
        Error::Protobuf(err)
    }
}

fn other_err(msg: String) -> Error {
    let err = io::Error::new(io::ErrorKind::Other, msg);
    convert::From::from(err)
}

pub type Result<T> = result::Result<T, Error>;

// Encodes message with message ID and protobuf body.
pub fn encode_msg<T: io::Write, M: protobuf::Message>(w: &mut T,
                                                      msg_id: u64,
                                                      msg: &M)
                                                      -> Result<()> {
    let payload_len = msg.compute_size();
    let header = encode_msg_header(msg_id, payload_len as usize);
    try!(w.write(&header));
    try!(msg.write_to_writer(w));

    Ok(())
}

// Decodes encoded message, returns message ID.
pub fn decode_msg<T: io::Read, M: protobuf::Message>(r: &mut T, m: &mut M) -> Result<u64> {
    let (message_id, payload) = try!(decode_data(r));
    try!(m.merge_from_bytes(&payload));

    Ok(message_id)
}

// Encodes data with message ID and any arbitrary body.
pub fn encode_data<T: io::Write>(w: &mut T, msg_id: u64, data: &[u8]) -> Result<()> {
    let header = encode_msg_header(msg_id, data.len());

    try!(w.write(&header));
    try!(w.write(data));

    Ok(())
}

// Decodes encoded data, returns message ID and body.
pub fn decode_data<T: io::Read>(r: &mut T) -> Result<(u64, Vec<u8>)> {
    let mut header = vec![0;MSG_HEADER_LEN];
    try!(r.read_exact(&mut header));

    let (msg_id, payload_len) = try!(decode_msg_header(&mut header));
    let mut payload = vec![0;payload_len];
    try!(r.read_exact(&mut payload));

    Ok((msg_id, payload))
}

// Encodes msg header to a 16 bytes header buffer.
pub fn encode_msg_header(msg_id: u64, payload_len: usize) -> Vec<u8> {
    let mut buf = vec![0;MSG_HEADER_LEN];

    BigEndian::write_u16(&mut buf[0..2], MSG_MAGIC);
    BigEndian::write_u16(&mut buf[2..4], MSG_VERSION_V1);
    BigEndian::write_u32(&mut buf[4..8], payload_len as u32);
    BigEndian::write_u64(&mut buf[8..16], msg_id);

    return buf;
}

// Decodes msg header in header buffer, the buffer length size must be equal MSG_HEADER_LEN;
pub fn decode_msg_header(header: &[u8]) -> Result<(u64, usize)> {
    let magic = BigEndian::read_u16(&header[0..2]);
    if MSG_MAGIC != magic {
        return Err(other_err(format!("invalid magic {}, not {}", magic, MSG_MAGIC)));
    }

    let version = BigEndian::read_u16(&header[2..4]);
    if MSG_VERSION_V1 != version {
        return Err(other_err(format!("unsupported version {}, we need {} now",
                                     version,
                                     MSG_VERSION_V1)));
    }

    let payload_len = BigEndian::read_u32(&header[4..8]) as usize;
    // TODO: check max payload

    let message_id = BigEndian::read_u64(&header[8..16]);

    Ok((message_id, payload_len))
}

#[cfg(test)]
mod tests {
    use bytes::ByteBuf;
    use std::io::Cursor;

    use super::*;
    use proto::raftpb::{Message, MessageType};

    #[test]
    fn test_msg_codec() {
        let mut m1 = Message::new();
        m1.set_field_type(MessageType::MsgBeat);

        let mut w = ByteBuf::mut_with_capacity(64);
        assert_eq!(encode_msg(&mut w, 1, &m1).is_ok(), true);

        let mut m2 = Message::new();
        assert_eq!(decode_msg(&mut w.flip(), &mut m2).unwrap(), 1);
        assert_eq!(m1, m2);
    }

    #[test]
    fn test_data_codec() {
        let body = vec![10;10];
        let mut m1 = vec![];
        encode_data(&mut m1, 1, &body).unwrap();

        let mut r = Cursor::new(m1.clone());
        let (msg_id, data) = decode_data(&mut r).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(&data, &body);
    }

    #[test]
    fn test_header_codec() {
        let m1 = encode_msg_header(1, 1);
        let (msg_id, payload_len) = decode_msg_header(&m1).unwrap();
        assert_eq!(msg_id, 1);
        assert_eq!(payload_len, 1);
    }
}
<|endoftext|>


<commit_before>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(s().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(iota().app(iota())), i());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(b().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(c().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(w().app(zero()).app(one())),
///            normalize(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(om().app(zero())), normalize(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
///
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_reduce();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(y().app(zero())), normalize(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<commit_msg>Adjust function name<commit_after>//! [Standard terms](https://en.wikipedia.org/wiki/Lambda_calculus#Standard_terms) and
//! [combinators](https://en.wikipedia.org/wiki/Combinatory_logic#Combinatory_calculi)
//!
//! * [SKI](https://en.wikipedia.org/wiki/SKI_combinator_calculus)
//! * [Iota](https://en.wikipedia.org/wiki/Iota_and_Jot)
//! * [BCKW](https://en.wikipedia.org/wiki/B,_C,_K,_W_system)
// //! * the recursion combinator U - needs more research
//! * the looping combinator ω
//! * the divergent combinator Ω
//! * [the fixed-point combinator Y](https://en.wikipedia.org/wiki/Fixed-point_combinator)

use term::*;
use term::Term::*;

/// I - the identity combinator.
///
/// I := λx.x = λ 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::i;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(i().app(zero())), zero());
/// ```
pub fn i() -> Term { abs(Var(1)) }

/// K - the constant / discarding combinator.
///
/// K := λxy.x = λ λ 2 = true
///
/// # Example
/// ```
/// use lambda_calculus::combinators::k;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(k().app(zero()).app(one())), zero());
/// ```
pub fn k() -> Term { abs(abs(Var(2))) }

/// S - the substitution combinator.
///
/// S := λxyz.x z (y z) = λ λ λ 3 1 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::s;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(s().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(Term::from(1).app(2.into()))));
/// ```
pub fn s() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2).app(Var(1)))
    )))
}

/// Iota - the universal combinator.
///
/// ι := λx.x S K = λ 1 S K
///
/// # Example
/// ```
/// use lambda_calculus::combinators::{iota, i, k, s};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(iota().app(iota())), i());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota())))), k());
/// assert_eq!(normalize(iota().app(iota().app(iota().app(iota().app(iota()))))), s());
/// ```
pub fn iota() -> Term { abs(Var(1).app(s()).app(k())) }

/// B - the composition combinator.
///
/// B := λxyz.x (y z) = λ λ λ 3 (2 1)
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::b;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(b().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(Term::from(1).app(2.into()))));
/// ```
pub fn b() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(2).app(Var(1)))
    )))
}

/// C - the swapping combinator.
///
/// C := λxyz.x z y = λ λ λ 3 1 2
///
/// # Example
/// ```
/// use lambda_calculus::term::Term;
/// use lambda_calculus::combinators::c;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(c().app(0.into()).app(1.into()).app(2.into())),
///            normalize(Term::from(0).app(2.into()).app(1.into())));
/// ```
pub fn c() -> Term {
    abs(abs(abs(
        Var(3)
        .app(Var(1))
        .app(Var(2))
    )))
}

/// W - the duplicating combinator.
///
/// W := λxy.x y y = λ λ 2 1 1
///
/// # Example
/// ```
/// use lambda_calculus::combinators::w;
/// use lambda_calculus::arithmetic::{zero, one};
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(w().app(zero()).app(one())),
///            normalize(zero().app(one()).app(one())));
/// ```
pub fn w() -> Term {
    abs(abs(
        Var(2)
        .app(Var(1))
        .app(Var(1))
    ))
}
/*
/// U - the recursion combinator.
///
/// U := λxy.y (x x y) = λ λ 1 (2 2 1)
pub fn u() -> Term { abs(abs(Var(1).app(Var(2).app(Var(2)).app(Var(1))))) }
*/
/// ω - the looping combinator.
///
/// ω := λx.x x
/// # Example
///
/// ```
/// use lambda_calculus::combinators::om;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(om().app(zero())), normalize(zero().app(zero())));
/// ```
pub fn om() -> Term { abs(Var(1).app(Var(1))) }

/// Ω - the divergent combinator.
///
/// Ω := ω ω
///
/// # Example
///
/// ```
/// use lambda_calculus::combinators::omm;
///
/// let mut doesnt_reduce = omm();
///
/// doesnt_reduce.beta_once();
///
/// assert_eq!(doesnt_reduce, omm());
/// ```
pub fn omm() -> Term { om().app(om()) }

/// Y - the fixed-point combinator.
///
/// Y := λg.(λx.g (x x)) (λx.g (x x)) = λ (λ 2 (1 1)) (λ 2 (1 1))
/// # Example
///
/// ```
/// use lambda_calculus::combinators::y;
/// use lambda_calculus::arithmetic::zero;
/// use lambda_calculus::reduction::normalize;
///
/// assert_eq!(normalize(y().app(zero())), normalize(zero().app(y().app(zero()))));
/// ```
pub fn y() -> Term {
    abs(app(
        abs(Var(2).app(Var(1).app(Var(1)))),
        abs(Var(2).app(Var(1).app(Var(1))))
    ))
}
<|endoftext|>


<commit_before>use std::io::Result;
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, UdpSocket};
use trust_dns_proto::op::Message;

pub trait Upstream {
    async fn lookup(&self, request: &Message) -> Result<Message>;
}

struct UdpUpstream {
    server: SocketAddr,
}

impl Upstream for UdpUpstream {
    async fn lookup(&self, request: &Message) -> Result<Message> {
        let socket = UdpSocket::bind(SocketAddr::new(match *self.server {
            SocketAddr::V4(..) => IpAddr::v4(Ipv4Addr::new(0, 0, 0, 0)),
            SocketAddr::V6(..) => IpAddr::v6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)),
        }, 0)).await?;
        socket.send_to(&request.to_vec()?, self.server).await?;
        let mut response = vec![0; 512];
        socket.recv_from(&mut response).await?;
        Ok(Message::from_vec(&response)?)
    }
}

struct Socks5UdpUpstream {
    server: SocketAddr,
}

impl Upstream for Socks5UdpUpstream {
    async fn lookup(&self, request: &Message) -> Result<Message> {
        let socket = UdpSocket::bind(SocketAddr::new(IpAddr::v4(Ipv4Addr::new(0, 0, 0, 0)), 0)).await?;
        unimplemented!()
    }
}

struct TcpUpstream {
    server: SocketAddr,
}

impl Upstream for TcpUpstream {
    async fn lookup(&self, request: &Message) -> Result<Message> {
        unimplemented!()
    }
}

#[cfg(any(target_os = "linux", target_os = "android"))]
struct UnixSocketUpstream {
    path: String,
}

#[cfg(any(target_os = "linux", target_os = "android"))]
impl Upstream for UnixSocketUpstream {
    async fn lookup(&self, request: &Message) -> Result<Message> {
        use tokio::net::UnixStream;
        let socket = UnixStream::connect(path).await?;
        unimplemented!()
    }
}
<commit_msg>Clean up<commit_after><|endoftext|>


<commit_before>//!CDRS support traffic decompression as it is described in [Apache
//!Cassandra protocol](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L790)
//!
//!Before being used, client and server must agree on a compression algorithm to
//!use, which is done in the STARTUP message. As a consequence, a STARTUP message
//!must never be compressed.  However, once the STARTUP frame has been received
//!by the server, messages can be compressed (including the response to the STARTUP
//!request).
//!
//!CDRS provides generic trait [`Compressor`][compressor].
//!Enum [`Compression`][compression] contains implementation
//!for `Compressor`.
//!
//!```no_run
//!use cdrs::client::CDRS;
//!use cdrs::query::QueryBuilder;
//!use cdrs::authenticators::NoneAuthenticator;
//!use cdrs::compression::Compression;
//!
//!let addr = "127.0.0.1:9042";
//!let tcp_transport = TransportTcp::new(addr).unwrap();
//!
//!// pass authenticator into CDRS' constructor
//!let client = CDRS::new(tcp_transport, NoneAuthenticator);
//!let session = client.start(Compression::None);
//!//let session = client.start(Compression::Lz4)
//!//let session = client.start(Compression::Snappy)
//!```
//![compression]:enum.Compression.html
//![compressor]:trait.Compressor.html

use std::convert::From;
use std::error::Error;
use std::result;
use std::fmt;
use std::io;

use snap;
use lz4_compress as lz4;

type Result<T> = result::Result<T, CompressionError>;

pub const LZ4: &'static str = "lz4";
pub const SNAPPY: &'static str = "snappy";

/// It's an error which may occure during encoding or deconding
/// frame body. As there are only two types of compressors it
/// contains two related enum options.
#[derive(Debug)]
pub enum CompressionError {
    /// Snappy error.
    Snappy(snap::Error),
    /// Lz4 error.
    Lz4(io::Error),
}

impl fmt::Display for CompressionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &CompressionError::Snappy(ref err) => write!(f, "Snappy Error: {:?}", err),
            &CompressionError::Lz4(ref err) => write!(f, "Lz4 Error: {:?}", err),
        }
    }
}

impl Error for CompressionError {
    fn description(&self) -> &str {
        match self {
            &CompressionError::Snappy(ref err) => err.description(),
            &CompressionError::Lz4(ref err) => err.description(),
        }
    }
}

/// Compressor trait that defines functionality
/// which should be provided by typical compressor.
pub trait Compressor {
    /// Encodes given bytes and returns `Result` that contains either
    /// encoded data or an error which occures during the transformation.
    fn encode(&self, bytes: Vec<u8>) -> Result<Vec<u8>>;
    /// Encodes given encoded data and returns `Result` that contains either
    /// encoded bytes or an error which occures during the transformation.
    fn decode(&self, bytes: Vec<u8>) -> Result<Vec<u8>>;
    /// Returns a string which is a name of a compressor. This name should be
    /// exactly the same as one which returns a server in a response to
    /// `Options` request.
    fn into_string(&self) -> Option<String>;
}

/// Enum which represents a type of compression. Only non-startup frame's body can be compressen.
#[derive(Debug, PartialEq, Clone, Copy, Eq, Ord, PartialOrd)]
pub enum Compression {
    /// [lz4](https://code.google.com/p/lz4/) compression
    Lz4,
    /// [snappy](https://code.google.com/p/snappy/) compression
    Snappy,
    /// Non compression
    None,
}

impl Compression {
    /// It encodes `bytes` basing on type of `Compression`..
    ///
    /// # Examples
    ///
    /// ```
    ///    use cdrs::compression::Compression;
    ///
    ///   let snappy_compression = Compression::Snappy;
    ///   let bytes = String::from("Hello World").into_bytes().to_vec();
    ///   let encoded = snappy_compression.encode(bytes.clone()).unwrap();
    ///   assert_eq!(snappy_compression.decode(encoded).unwrap(), bytes);
    ///
    /// ```
    pub fn encode(&self, bytes: Vec<u8>) -> Result<Vec<u8>> {
        match self {
            &Compression::Lz4 => Compression::encode_lz4(bytes),
            &Compression::Snappy => Compression::encode_snappy(bytes),
            &Compression::None => Ok(bytes),
        }
    }

    /// It decodes `bytes` basing on type of compression.
    ///
    /// # Examples
    ///
    /// ```
    ///    use cdrs::compression::Compression;
    ///     let lz4_compression = Compression::Lz4;
    ///     let bytes = String::from("Hello World").into_bytes().to_vec();
    ///     let encoded = lz4_compression.encode(bytes.clone()).unwrap();
    ///     let len = encoded.len() as u8;
    ///     let mut input = vec![0, 0, 0, len];
    ///     input.extend_from_slice(encoded.as_slice());
    ///     assert_eq!(lz4_compression.decode(input).unwrap(), bytes);
    /// ```
    pub fn decode(&self, bytes: Vec<u8>) -> Result<Vec<u8>> {
        match self {
            &Compression::Lz4 => Compression::decode_lz4(bytes),
            &Compression::Snappy => Compression::decode_snappy(bytes),
            &Compression::None => Ok(bytes),
        }
    }

    /// It transforms compression method into a `&str`.
    pub fn as_str(&self) -> Option<&'static str> {
        match self {
            &Compression::Lz4 => Some(LZ4),
            &Compression::Snappy => Some(SNAPPY),
            &Compression::None => None,
        }
    }

    fn encode_snappy(bytes: Vec<u8>) -> Result<Vec<u8>> {
        let mut encoder = snap::Encoder::new();
        encoder
            .compress_vec(bytes.as_slice())
            .map_err(CompressionError::Snappy)
    }

    fn decode_snappy(bytes: Vec<u8>) -> Result<Vec<u8>> {
        let mut decoder = snap::Decoder::new();
        decoder
            .decompress_vec(bytes.as_slice())
            .map_err(CompressionError::Snappy)
    }

    fn encode_lz4(bytes: Vec<u8>) -> Result<Vec<u8>> {
        return Ok(lz4::compress(bytes.as_slice()));
    }

    fn decode_lz4(bytes: Vec<u8>) -> Result<Vec<u8>> {
        // skip first 4 bytes in accordance to
        // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L805
        lz4::decompress(&bytes[4..]).map_err(CompressionError::Lz4)
    }
}

impl From<String> for Compression {
    /// It converts `String` into `Compression`. If string is neither `lz4` nor `snappy` then
    /// `Compression::None` will be returned
    fn from(compression_string: String) -> Compression {
        return Compression::from(compression_string.as_str());
    }
}

impl<'a> From<&'a str> for Compression {
    /// It converts `str` into `Compression`. If string is neither `lz4` nor `snappy` then
    /// `Compression::None` will be returned
    fn from(compression_str: &'a str) -> Compression {
        match compression_str {
            LZ4 => Compression::Lz4,
            SNAPPY => Compression::Snappy,
            _ => Compression::None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_compression_from_str() {
        let lz4 = "lz4";
        assert_eq!(Compression::from(lz4), Compression::Lz4);
        let snappy = "snappy";
        assert_eq!(Compression::from(snappy), Compression::Snappy);
        let none = "x";
        assert_eq!(Compression::from(none), Compression::None);
    }

    #[test]
    fn test_compression_from_string() {
        let lz4 = "lz4".to_string();
        assert_eq!(Compression::from(lz4), Compression::Lz4);
        let snappy = "snappy".to_string();
        assert_eq!(Compression::from(snappy), Compression::Snappy);
        let none = "x".to_string();
        assert_eq!(Compression::from(none), Compression::None);
    }

    #[test]
    fn test_compression_encode_snappy() {
        let snappy_compression = Compression::Snappy;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        snappy_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_snappy() {
        let snappy_compression = Compression::Snappy;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = snappy_compression.encode(bytes.clone()).unwrap();
        assert_eq!(snappy_compression.decode(encoded).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_lz4() {
        let snappy_compression = Compression::Lz4;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        snappy_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_lz4() {
        let lz4_compression = Compression::Lz4;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = lz4_compression.encode(bytes.clone()).unwrap();
        let len = encoded.len() as u8;
        let mut input = vec![0, 0, 0, len];
        input.extend_from_slice(encoded.as_slice());
        assert_eq!(lz4_compression.decode(input).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_none() {
        let none_compression = Compression::None;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        none_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_none() {
        let none_compression = Compression::None;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = none_compression.encode(bytes.clone()).unwrap();
        assert_eq!(none_compression.decode(encoded).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_lz4_with_invalid_input() {
        let lz4_compression = Compression::Lz4;
        let bytes: Vec<u8> = vec![0x7f, 0x7f, 0x7f, 0x7f, 0x7f];
        let encoded = lz4_compression.encode(bytes.clone()).unwrap();
        let decode = lz4_compression.decode(encoded);
        assert_eq!(decode.is_err(), true);
    }

    #[test]
    fn test_compression_encode_snappy_with_non_utf8() {
        let snappy_compression = Compression::Snappy;
        let v = vec![0xff, 0xff];
        let encoded = snappy_compression
            .encode(v.clone())
            .expect("Should work without exceptions");
        assert_eq!(snappy_compression.decode(encoded).unwrap(), v);
    }

}
<commit_msg>Fix compression docs<commit_after>//!CDRS support traffic decompression as it is described in [Apache
//!Cassandra protocol](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L790)
//!
//!Before being used, client and server must agree on a compression algorithm to
//!use, which is done in the STARTUP message. As a consequence, a STARTUP message
//!must never be compressed.  However, once the STARTUP frame has been received
//!by the server, messages can be compressed (including the response to the STARTUP
//!request).
//!
//!CDRS provides generic trait [`Compressor`][compressor].
//!Enum [`Compression`][compression] contains implementation
//!for `Compressor`.
//!
//!```no_run
//!use cdrs::client::CDRS;
//!use cdrs::query::QueryBuilder;
//!use cdrs::authenticators::NoneAuthenticator;
//!use cdrs::compression::Compression;
//!use cdrs::transport::TransportTcp;
//!
//!let addr = "127.0.0.1:9042";
//!let tcp_transport = TransportTcp::new(addr).unwrap();
//!
//!// pass authenticator into CDRS' constructor
//!let client = CDRS::new(tcp_transport, NoneAuthenticator);
//!let session = client.start(Compression::None);
//!//let session = client.start(Compression::Lz4)
//!//let session = client.start(Compression::Snappy)
//!```
//![compression]:enum.Compression.html
//![compressor]:trait.Compressor.html

use std::convert::From;
use std::error::Error;
use std::result;
use std::fmt;
use std::io;

use snap;
use lz4_compress as lz4;

type Result<T> = result::Result<T, CompressionError>;

pub const LZ4: &'static str = "lz4";
pub const SNAPPY: &'static str = "snappy";

/// It's an error which may occure during encoding or deconding
/// frame body. As there are only two types of compressors it
/// contains two related enum options.
#[derive(Debug)]
pub enum CompressionError {
    /// Snappy error.
    Snappy(snap::Error),
    /// Lz4 error.
    Lz4(io::Error),
}

impl fmt::Display for CompressionError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &CompressionError::Snappy(ref err) => write!(f, "Snappy Error: {:?}", err),
            &CompressionError::Lz4(ref err) => write!(f, "Lz4 Error: {:?}", err),
        }
    }
}

impl Error for CompressionError {
    fn description(&self) -> &str {
        match self {
            &CompressionError::Snappy(ref err) => err.description(),
            &CompressionError::Lz4(ref err) => err.description(),
        }
    }
}

/// Compressor trait that defines functionality
/// which should be provided by typical compressor.
pub trait Compressor {
    /// Encodes given bytes and returns `Result` that contains either
    /// encoded data or an error which occures during the transformation.
    fn encode(&self, bytes: Vec<u8>) -> Result<Vec<u8>>;
    /// Encodes given encoded data and returns `Result` that contains either
    /// encoded bytes or an error which occures during the transformation.
    fn decode(&self, bytes: Vec<u8>) -> Result<Vec<u8>>;
    /// Returns a string which is a name of a compressor. This name should be
    /// exactly the same as one which returns a server in a response to
    /// `Options` request.
    fn into_string(&self) -> Option<String>;
}

/// Enum which represents a type of compression. Only non-startup frame's body can be compressen.
#[derive(Debug, PartialEq, Clone, Copy, Eq, Ord, PartialOrd)]
pub enum Compression {
    /// [lz4](https://code.google.com/p/lz4/) compression
    Lz4,
    /// [snappy](https://code.google.com/p/snappy/) compression
    Snappy,
    /// Non compression
    None,
}

impl Compression {
    /// It encodes `bytes` basing on type of `Compression`..
    ///
    /// # Examples
    ///
    /// ```
    ///    use cdrs::compression::Compression;
    ///
    ///   let snappy_compression = Compression::Snappy;
    ///   let bytes = String::from("Hello World").into_bytes().to_vec();
    ///   let encoded = snappy_compression.encode(bytes.clone()).unwrap();
    ///   assert_eq!(snappy_compression.decode(encoded).unwrap(), bytes);
    ///
    /// ```
    pub fn encode(&self, bytes: Vec<u8>) -> Result<Vec<u8>> {
        match self {
            &Compression::Lz4 => Compression::encode_lz4(bytes),
            &Compression::Snappy => Compression::encode_snappy(bytes),
            &Compression::None => Ok(bytes),
        }
    }

    /// It decodes `bytes` basing on type of compression.
    ///
    /// # Examples
    ///
    /// ```
    ///    use cdrs::compression::Compression;
    ///     let lz4_compression = Compression::Lz4;
    ///     let bytes = String::from("Hello World").into_bytes().to_vec();
    ///     let encoded = lz4_compression.encode(bytes.clone()).unwrap();
    ///     let len = encoded.len() as u8;
    ///     let mut input = vec![0, 0, 0, len];
    ///     input.extend_from_slice(encoded.as_slice());
    ///     assert_eq!(lz4_compression.decode(input).unwrap(), bytes);
    /// ```
    pub fn decode(&self, bytes: Vec<u8>) -> Result<Vec<u8>> {
        match self {
            &Compression::Lz4 => Compression::decode_lz4(bytes),
            &Compression::Snappy => Compression::decode_snappy(bytes),
            &Compression::None => Ok(bytes),
        }
    }

    /// It transforms compression method into a `&str`.
    pub fn as_str(&self) -> Option<&'static str> {
        match self {
            &Compression::Lz4 => Some(LZ4),
            &Compression::Snappy => Some(SNAPPY),
            &Compression::None => None,
        }
    }

    fn encode_snappy(bytes: Vec<u8>) -> Result<Vec<u8>> {
        let mut encoder = snap::Encoder::new();
        encoder
            .compress_vec(bytes.as_slice())
            .map_err(CompressionError::Snappy)
    }

    fn decode_snappy(bytes: Vec<u8>) -> Result<Vec<u8>> {
        let mut decoder = snap::Decoder::new();
        decoder
            .decompress_vec(bytes.as_slice())
            .map_err(CompressionError::Snappy)
    }

    fn encode_lz4(bytes: Vec<u8>) -> Result<Vec<u8>> {
        return Ok(lz4::compress(bytes.as_slice()));
    }

    fn decode_lz4(bytes: Vec<u8>) -> Result<Vec<u8>> {
        // skip first 4 bytes in accordance to
        // https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v4.spec#L805
        lz4::decompress(&bytes[4..]).map_err(CompressionError::Lz4)
    }
}

impl From<String> for Compression {
    /// It converts `String` into `Compression`. If string is neither `lz4` nor `snappy` then
    /// `Compression::None` will be returned
    fn from(compression_string: String) -> Compression {
        return Compression::from(compression_string.as_str());
    }
}

impl<'a> From<&'a str> for Compression {
    /// It converts `str` into `Compression`. If string is neither `lz4` nor `snappy` then
    /// `Compression::None` will be returned
    fn from(compression_str: &'a str) -> Compression {
        match compression_str {
            LZ4 => Compression::Lz4,
            SNAPPY => Compression::Snappy,
            _ => Compression::None,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn test_compression_from_str() {
        let lz4 = "lz4";
        assert_eq!(Compression::from(lz4), Compression::Lz4);
        let snappy = "snappy";
        assert_eq!(Compression::from(snappy), Compression::Snappy);
        let none = "x";
        assert_eq!(Compression::from(none), Compression::None);
    }

    #[test]
    fn test_compression_from_string() {
        let lz4 = "lz4".to_string();
        assert_eq!(Compression::from(lz4), Compression::Lz4);
        let snappy = "snappy".to_string();
        assert_eq!(Compression::from(snappy), Compression::Snappy);
        let none = "x".to_string();
        assert_eq!(Compression::from(none), Compression::None);
    }

    #[test]
    fn test_compression_encode_snappy() {
        let snappy_compression = Compression::Snappy;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        snappy_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_snappy() {
        let snappy_compression = Compression::Snappy;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = snappy_compression.encode(bytes.clone()).unwrap();
        assert_eq!(snappy_compression.decode(encoded).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_lz4() {
        let snappy_compression = Compression::Lz4;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        snappy_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_lz4() {
        let lz4_compression = Compression::Lz4;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = lz4_compression.encode(bytes.clone()).unwrap();
        let len = encoded.len() as u8;
        let mut input = vec![0, 0, 0, len];
        input.extend_from_slice(encoded.as_slice());
        assert_eq!(lz4_compression.decode(input).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_none() {
        let none_compression = Compression::None;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        none_compression
            .encode(bytes.clone())
            .expect("Should work without exceptions");
    }

    #[test]
    fn test_compression_decode_none() {
        let none_compression = Compression::None;
        let bytes = String::from("Hello World").into_bytes().to_vec();
        let encoded = none_compression.encode(bytes.clone()).unwrap();
        assert_eq!(none_compression.decode(encoded).unwrap(), bytes);
    }

    #[test]
    fn test_compression_encode_lz4_with_invalid_input() {
        let lz4_compression = Compression::Lz4;
        let bytes: Vec<u8> = vec![0x7f, 0x7f, 0x7f, 0x7f, 0x7f];
        let encoded = lz4_compression.encode(bytes.clone()).unwrap();
        let decode = lz4_compression.decode(encoded);
        assert_eq!(decode.is_err(), true);
    }

    #[test]
    fn test_compression_encode_snappy_with_non_utf8() {
        let snappy_compression = Compression::Snappy;
        let v = vec![0xff, 0xff];
        let encoded = snappy_compression
            .encode(v.clone())
            .expect("Should work without exceptions");
        assert_eq!(snappy_compression.decode(encoded).unwrap(), v);
    }

}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use tokenizer::tokenizer::box_tokenizer;
use tokenizer::BoxedTokenizer;
use tokenizer::JapaneseTokenizer;
use tokenizer::LowerCaser;
use tokenizer::RawTokenizer;
use tokenizer::RemoveLongFilter;
use tokenizer::SimpleTokenizer;
use tokenizer::Stemmer;
use tokenizer::StopWordFilter;
use tokenizer::Tokenizer;

/// The tokenizer manager serves as a store for
/// all of the pre-configured tokenizer pipelines.
///
/// By default, it is populated with the following managers.
///
///  * `raw` : does not process nor tokenize the text.
///  * `default` : Chops the text on according to whitespace and
///  punctuation, removes tokens that are too long, and lowercases
///  tokens
///  * `en_stem` : Like `default`, but also applies stemming on the
///  resulting tokens. Stemming can improve the recall of your
///  search engine.
#[derive(Clone)]
pub struct TokenizerManager {
    tokenizers: Arc<RwLock<HashMap<String, Box<BoxedTokenizer>>>>,
}

impl TokenizerManager {
    /// Registers a new tokenizer associated with a given name.
    pub fn register<A>(&self, tokenizer_name: &str, tokenizer: A)
    where
        A: 'static + Send + Sync + for<'a> Tokenizer<'a>,
    {
        let boxed_tokenizer = box_tokenizer(tokenizer);
        self.tokenizers
            .write()
            .expect("Acquiring the lock should never fail")
            .insert(tokenizer_name.to_string(), boxed_tokenizer);
    }

    /// Accessing a tokenizer given its name.
    pub fn get(&self, tokenizer_name: &str) -> Option<Box<BoxedTokenizer>> {
        self.tokenizers
            .read()
            .expect("Acquiring the lock should never fail")
            .get(tokenizer_name)
            .map(|boxed_tokenizer| boxed_tokenizer.boxed_clone())
    }
}

impl Default for TokenizerManager {
    /// Creates an `TokenizerManager` prepopulated with
    /// the default pre-configured tokenizers of `tantivy`.
    /// - simple
    /// - en_stem
    /// - ja
    fn default() -> TokenizerManager {
        let manager = TokenizerManager {
            tokenizers: Arc::new(RwLock::new(HashMap::new())),
        };
        manager.register("raw", RawTokenizer);
        manager.register(
            "default",
            SimpleTokenizer
                .filter(RemoveLongFilter::limit(40))
                .filter(LowerCaser),
        );
        manager.register(
            "en_stem",
            SimpleTokenizer
                .filter(RemoveLongFilter::limit(40))
                .filter(LowerCaser)
                .filter(Stemmer::new()),
        );
        manager.register("ja", JapaneseTokenizer.filter(RemoveLongFilter::limit(40)));
        manager
    }
}
<commit_msg>Removed use<commit_after>use std::collections::HashMap;
use std::sync::{Arc, RwLock};
use tokenizer::tokenizer::box_tokenizer;
use tokenizer::BoxedTokenizer;
use tokenizer::JapaneseTokenizer;
use tokenizer::LowerCaser;
use tokenizer::RawTokenizer;
use tokenizer::RemoveLongFilter;
use tokenizer::SimpleTokenizer;
use tokenizer::Stemmer;
use tokenizer::Tokenizer;

/// The tokenizer manager serves as a store for
/// all of the pre-configured tokenizer pipelines.
///
/// By default, it is populated with the following managers.
///
///  * `raw` : does not process nor tokenize the text.
///  * `default` : Chops the text on according to whitespace and
///  punctuation, removes tokens that are too long, and lowercases
///  tokens
///  * `en_stem` : Like `default`, but also applies stemming on the
///  resulting tokens. Stemming can improve the recall of your
///  search engine.
#[derive(Clone)]
pub struct TokenizerManager {
    tokenizers: Arc<RwLock<HashMap<String, Box<BoxedTokenizer>>>>,
}

impl TokenizerManager {
    /// Registers a new tokenizer associated with a given name.
    pub fn register<A>(&self, tokenizer_name: &str, tokenizer: A)
    where
        A: 'static + Send + Sync + for<'a> Tokenizer<'a>,
    {
        let boxed_tokenizer = box_tokenizer(tokenizer);
        self.tokenizers
            .write()
            .expect("Acquiring the lock should never fail")
            .insert(tokenizer_name.to_string(), boxed_tokenizer);
    }

    /// Accessing a tokenizer given its name.
    pub fn get(&self, tokenizer_name: &str) -> Option<Box<BoxedTokenizer>> {
        self.tokenizers
            .read()
            .expect("Acquiring the lock should never fail")
            .get(tokenizer_name)
            .map(|boxed_tokenizer| boxed_tokenizer.boxed_clone())
    }
}

impl Default for TokenizerManager {
    /// Creates an `TokenizerManager` prepopulated with
    /// the default pre-configured tokenizers of `tantivy`.
    /// - simple
    /// - en_stem
    /// - ja
    fn default() -> TokenizerManager {
        let manager = TokenizerManager {
            tokenizers: Arc::new(RwLock::new(HashMap::new())),
        };
        manager.register("raw", RawTokenizer);
        manager.register(
            "default",
            SimpleTokenizer
                .filter(RemoveLongFilter::limit(40))
                .filter(LowerCaser),
        );
        manager.register(
            "en_stem",
            SimpleTokenizer
                .filter(RemoveLongFilter::limit(40))
                .filter(LowerCaser)
                .filter(Stemmer::new()),
        );
        manager.register("ja", JapaneseTokenizer.filter(RemoveLongFilter::limit(40)));
        manager
    }
}
<|endoftext|>


<commit_before>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

#[test]
fn test_min_dx() {
    use std::iter::FromIterator;
    use std::cmp::Ordering;

    // 1. prepare none-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );
    x.sort_by(|&x,&y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );
    // FIXME
    //let delta_x = x - &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
    //                    0.8284895327495356, 0.9760168013869176, 0.9938640428738624];
    assert!(true);
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let min_dx = x.windows(2) // iterator for adjacent pairs of a slice
                  .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
                  .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`

    let dt = cfl*min_dx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<commit_msg>finished unit_test for min_dx.<commit_after>//***********************************************************************
//  Copyright 2006 John A. Trangenstein
//
//  This software is made available for research and instructional use
//  only.e available for research and instructional use
//  only.
//  You may copy and use this software without charge for these
//  non-commercial purposes, provided that the copyright notice and
//  associated text is reproduced on all copies.
//  For all other uses (including distribution of modified versions),
//  please contact the author at
//    John A. Trangenstein
//    Department of Mathematics
//    Duke University
//    Durham, NC 27708-0320
//    USA
//  or
//    johnt@math.duke.edu
//
//  This software is made available "as is" without any assurance that it
//  is completely correct, or that it will work for your purposes.
//  Use the software at your own risk.
//***********************************************************************

// Permission to publish the translation of the code
// was graciously granted by Prof. John A. Trangenstein

// The MIT License (MIT)
//
// Copyright (c) 2015 Alexander Samoilov
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.

#![feature(duration_span)]

extern crate argparse;
extern crate num;

use num::{Num, Zero, One, Signed};

use std::time::Duration;
use std::cmp;
use std::process::exit;
use argparse::{ArgumentParser, StoreTrue, Store};

struct Options {
    verbose: bool,
    num_steps: usize,
    num_cells: usize,
    num_runs: usize,
}

fn do_computation(nsteps: usize, ncells: usize, tmax: f64, ifirst: usize, ilast: usize,
                  statelft: f64, statergt: f64, velocity: f64, dt: f64,
                  fc: usize, lc: usize, x: &Vec<f64>, u: &mut Vec<f64>)
{
    let mut istep   =   0;
    let mut t       =   0.0f64;
    let mut flux    =   vec![0.0f64; x.len()];

    // loop over timesteps
    while istep < nsteps && t < tmax {

        // right boundary condition: outgoing wave
        for ic in ncells .. lc {
            u[ic]=u[ncells-1];
        }
        // left boundary condition: specified value
        for ic in 0 .. fc {
            u[ic]=statelft;
        }

        // upwind fluxes times dt (ie, flux time integral over cell side)
        // assumes velocity > 0
        let vdt=velocity*dt;
        for ie in ifirst .. ilast+1 {
            flux[ie]=vdt*u[ie-1];
        }

        // conservative difference
        for ic in ifirst .. ilast {
            u[ic] -= (flux[ic+1]-flux[ic]) / (x[ic+1]-x[ic])
        }

        // update time and step number
        t       +=  dt;
        istep   +=  1
    }
}

fn min_dx(x: &[f64]) -> f64 {
    // https://doc.rust-lang.org/std/primitive.slice.html#method.windows
    let mdx = x.windows(2) // iterator for adjacent pairs of a slice
               .map(|w| w[1]-w[0]) // i.e. [x[0], x[1]], [x[1], x[2]] ...
               .fold(std::f64::MAX, |x1, x2| x1.min(x2)); // `fold` to find `min`
    mdx
}

#[test]
fn test_min_dx() {
    use std::iter::FromIterator;
    use std::cmp::Ordering;

    fn sub<T: Num + Copy>(lhs: &[T], rhs: &[T]) -> Vec<T> {
        Vec::from_iter (lhs.iter().zip(rhs.iter()) .map(|(&x,&y)| x - y ) )
    }

    // 1. prepare non-equidistant vector `x`
    let base_dx = std::f64::consts::FRAC_PI_4; // 0.785398
    let mut x = Vec::from_iter ((1..7) .map(|idx| ((idx as f64).sin() * base_dx).cos().abs() ) );

    x.sort_by(|&x, &y|
        if      x < y { Ordering::Less }
        else if x > y { Ordering::Greater }
        else { Ordering::Equal } );

    let delta_x = sub(&x, &[0.7295467223444416, 0.7556433468867207, 0.7894463883160331,
                            0.8284895327495356, 0.9760168013869176, 0.9938640428738624]);

    let inf_norm = delta_x .iter() .fold(delta_x[0].abs(), |x1, x2| (x1).max((*x2).abs()));

    assert!(inf_norm < 1e-10, "inf_norm");

    // classical way
    let mut min_dx1 = std::f64::MAX;
    for i in 0 .. x.len()-1 {
        min_dx1 = min_dx1.min(x[i+1]-x[i]);
    }

    // functional way
    let min_dx2 = min_dx(&x);
    let abs_delta = (min_dx1 - min_dx2).abs();
    println!("abs_delta : {} min_dx1 : {} min_dx2 : {} x : {:?}", abs_delta, min_dx1, min_dx2, x);
    assert!(abs_delta < 1e-10, "min_dx");
}

fn main() {
    let mut options = Options {
        verbose:   false,
        num_steps: 2000,
        num_cells: 2000,
        num_runs:  10,
    };

    {
        let mut ap = ArgumentParser::new();
        ap.set_description("Time elapsing of model PDE for scalar conservation law.");
        ap.refer(&mut options.verbose)
            .add_option(&["-v", "--verbose"], StoreTrue,
            "set verbose");
        ap.refer(&mut options.num_steps)
            .add_option(&["-t", "--num_steps"], Store,
            "set number of time steps");
        ap.refer(&mut options.num_cells)
            .add_option(&["-n", "--num_cells"], Store,
            "set number of grid cells");
        ap.refer(&mut options.num_runs)
            .add_option(&["-b", "--num_runs"], Store,
            "set number of runs");
        match ap.parse_args() {
            Ok(()) => {}
            Err(x) => {
                exit(x);
            }
        }
    }

    if options.verbose {
        println!("number of time steps : {} number of grid cells : {} number of runs : {}",
                 options.num_steps, options.num_cells, options.num_runs);
    }

    // problem-specific parameters:
    const jump     : f64   =  0.0f64;
    const x_left   : f64   = -0.2f64;
    const x_right  : f64   =  1.0f64;
    const statelft : f64   =  2.0f64;
    const statergt : f64   =  0.0f64;
    const velocity : f64   =  1.0f64;

    const tmax     : f64   =  0.8f64;
    const cfl      : f64   =  0.9f64;

    // array bounds:
    let   nsteps           = options.num_steps;
    let   ncells           = options.num_cells;
    const fc       : usize = 2;
    let   lc               = ncells+1;
    const ifirst   : usize = 1;
    let   ilast            = ncells-1;

    // work arrays
    // #   double precision
    // #  &  u(-2:ncells+1),
    // #  &  x(0:ncells),
    // #  &  flux(0:ncells)

    let mut u    = vec![0.0f64; ncells+4];
    let mut x    = vec![0.0f64; ncells+1];

    //  uniform mesh:
    let dx = (x_right-x_left) / ncells as f64;
    for ie in ifirst .. ilast+1 {
        x[ie] = x_left + ie as f64 * dx;
    }

    // initial values for diffential equation:
    let ijump = cmp::max(ifirst as isize -1,
                         cmp::min((ncells as f64 * (jump-x_left)/(x_right-x_left) + 0.5) as isize,
                                  (ilast+1) as isize)) as usize;
    if options.verbose {
        println!("ijump : {}", ijump);
    }

    // stable timestep (independent of time for linear advection):
    let mindx = min_dx(&x);
    let dt = cfl*mindx/velocity.abs();

    let d = Duration::span(||{
        for r in 0..options.num_runs {
            if options.verbose {
                println!("run number : {}", r);
            }

            // left state to left of jump
            for ic in ifirst .. ijump-1 {
                u[ic+3] = statelft;
            }

            // volume-weighted average in cell containing jump
            let frac = (jump-x_left-ijump as f64 *dx)/(x_right-x_left);
            u[ijump+3] = statelft*frac+statergt*(1.0f64-frac);

            // right state to right of jump
            for ic in ijump+1 .. ilast {
                u[ic+3]=statergt;
            }

            do_computation(nsteps, ncells, tmax, ifirst, ilast,
                           statelft, statergt, velocity, dt, fc, lc, &x, &mut u);
        }
    });
    println!("elapsed time: {}", d.as_secs() as f64 + d.subsec_nanos() as f64 / 1.0e9f64);
}
<|endoftext|>


<commit_before>extern crate find_folder;

use screen::*;
use piston_window;
use conrod;
use conrod::Widget;
use conrod::Frameable;
use conrod::color::Colorable;
use conrod::Positionable;

pub struct MainMenuScreen {
    ui: conrod::Ui,
}

impl MainMenuScreen {
    pub fn new() -> MainMenuScreen {
        MainMenuScreen { ui: create_ui() }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input, window: &piston_window::PistonWindow) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        // TODO: Move Ui to some context?
        // piston_window::Glyphs
        // type Ui = conrod::Ui<Glyphs>;
        let mut ui = {
            let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
            let font_path = assets.join("NotoSans-Regular.ttf");
            let theme = conrod::Theme::default();
            let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
            conrod::Ui::new(glyph_cache.unwrap(), theme)
        };

        ui.handle_event(window);

        ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Widget Demonstration")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);
        });

        window.draw_2d(|context, graphics| ui.draw(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {}
}

widget_ids! {
    CANVAS,
    TITLE,
}

fn create_ui() -> conrod::Ui {
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
    let font_path = assets.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<commit_msg>Work in progress<commit_after>extern crate find_folder;

use screen::*;
use piston_window;
use conrod;
use conrod::Widget;
use conrod::Frameable;
use conrod::color::Colorable;
use conrod::Positionable;

pub struct MainMenuScreen {
    ui: conrod::Ui<Glyphs>,
}

impl MainMenuScreen {
    pub fn new(window: &piston_window::PistonWindow) -> MainMenuScreen {
        MainMenuScreen { ui: create_ui(&window) }
    }
}

impl Screen for MainMenuScreen {
    fn on_input(&mut self, input: &piston_window::Input, window: &piston_window::PistonWindow) -> InputResults {
        use piston_window::{Input, Button, MouseButton};

        let mut result = Vec::new();

        match input {
            &Input::Press(Button::Mouse(MouseButton::Left)) => {
                result.push(InputResult::PopScreen);
                result.push(InputResult::PushScreen(Box::new(BattleScreen::new(&window))));
            }
            _ => {}
        }

        result
    }

    fn on_draw(&mut self, args: &piston_window::RenderArgs, window: &piston_window::PistonWindow) {
        // TODO: Move Ui to some context?
        // piston_window::Glyphs
        // type Ui = conrod::Ui<Glyphs>;
        let mut ui = {
            let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
            let font_path = assets.join("NotoSans-Regular.ttf");
            let theme = conrod::Theme::default();
            let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
            conrod::Ui::new(glyph_cache.unwrap(), theme)
        };

        ui.handle_event(window);

        ui.set_widgets(|ui| {
            conrod::Canvas::new()
                .frame(200.)
                .pad(30.0)
                .color(conrod::color::rgb(0.2, 0.35, 0.45))
                .scroll_kids()
                .set(CANVAS, ui);

            conrod::Text::new("Widget Demonstration")
                .top_left_with_margins_on(CANVAS, 0.0, 350.0)
                .font_size(32)
                .color(conrod::color::rgb(0.2, 0.35, 0.45).plain_contrast())
                .set(TITLE, ui);
        });

        window.draw_2d(|context, graphics| ui.draw(context, graphics));
    }

    fn on_update(&mut self, args: &piston_window::UpdateArgs) {}
}

widget_ids! {
    CANVAS,
    TITLE,
}

fn create_ui(window: &piston_window::PistonWindow) -> conrod::Ui {
    let assets = find_folder::Search::KidsThenParents(3, 5).for_folder("assets").unwrap();
    let font_path = assets.join("NotoSans-Regular.ttf");
    let theme = conrod::Theme::default();
    let glyph_cache = piston_window::Glyphs::new(&font_path, window.factory.borrow().clone());
    conrod::Ui::new(glyph_cache.unwrap(), theme)
}
<|endoftext|>


<commit_before>use serialize::json;

pub struct Description {
    pub name: Option<String>,
    pub designer: Option<String>,
    pub url: Option<String>,
}

#[deriving(Decodable)]
struct MetaData {
    name: String,
    designer: String,
}

impl Description {
    #[inline]
    fn new() -> Description {
        Description {
            name: None,
            designer: None,
            url: None,
        }
    }

    pub fn load(path: &Path) -> Description {
        let mut desc = Description::new();

        Description::populate_by_metadata(&mut desc, path);
        Description::populate_by_inference(&mut desc, path);
        Description::populate_by_guessing(&mut desc, path);

        desc
    }

    fn populate_by_metadata(desc: &mut Description, path: &Path) {
        use std::io::fs;
        use std::io::fs::PathExtensions;

        macro_rules! ok(
            ($result:expr) => {
                match $result {
                    Ok(result) => result,
                    Err(_) => return,
                }
            };
        )

        let path = path.dir_path().join("METADATA.json");

        if !path.exists() {
            return;
        }

        let content = ok!(ok!(fs::File::open(&path)).read_to_string());

        match json::decode::<MetaData>(content.as_slice()) {
            Ok(metadata) => {
                if !metadata.name.is_empty() {
                    desc.name = Some(metadata.name);
                }
                if !metadata.designer.is_empty() {
                    desc.designer = Some(metadata.designer);
                }
            },
            Err(_) => {},
        }
    }

    fn populate_by_inference(desc: &mut Description, path: &Path) {
        if desc.name.is_some() {
            return;
        }

        match path.extension() {
            Some(b"ttf") | Some(b"TTF") => {},
            _ => return,
        }

        let path = path.with_extension("");
        let blob = match path.filename_str() {
            Some(blob) => blob,
            _ => return,
        };

        let blob = match blob.split('-').next() {
            Some(blob) => blob,
            _ => return,
        };

        let mut name = String::new();
        for (i, c) in blob.char_indices() {
            match c {
                'A'...'Z' if i > 0 => {
                    name.push(' ');
                    name.push(c);
                },
                _ => {
                    name.push(c);
                },
            }
        }

        if !name.is_empty() {
            desc.name = Some(name);
        }
    }

    fn populate_by_guessing(desc: &mut Description, _: &Path) {
        let chunks = match desc.name {
            Some(ref name) => name.as_slice().split(' ').collect::<Vec<_>>(),
            None => return,
        };

        for count in range(1, chunks.len()).rev() {
            let mut name = String::new();
            for &chunk in chunks.iter().take(count) {
                if !name.is_empty() {
                    name.push('+');
                }
                name.push_str(chunk);
            }

            let url = format!("https://www.google.com/fonts/specimen/{}", name);
            if ping(url.as_slice()) {
                desc.url = Some(url);
                break;
            }
        }
    }
}

fn ping(url: &str) -> bool {
    use curl::http;
    match http::handle().head(url).exec() {
        Ok(response) => response.get_code() == 200,
        Err(_) => false,
    }
}
<commit_msg>Fixed a bug in searching for URLs<commit_after>use serialize::json;

pub struct Description {
    pub name: Option<String>,
    pub designer: Option<String>,
    pub url: Option<String>,
}

#[deriving(Decodable)]
struct MetaData {
    name: String,
    designer: String,
}

impl Description {
    #[inline]
    fn new() -> Description {
        Description {
            name: None,
            designer: None,
            url: None,
        }
    }

    pub fn load(path: &Path) -> Description {
        let mut desc = Description::new();

        Description::populate_by_metadata(&mut desc, path);
        Description::populate_by_inference(&mut desc, path);
        Description::populate_by_guessing(&mut desc, path);

        desc
    }

    fn populate_by_metadata(desc: &mut Description, path: &Path) {
        use std::io::fs;
        use std::io::fs::PathExtensions;

        macro_rules! ok(
            ($result:expr) => {
                match $result {
                    Ok(result) => result,
                    Err(_) => return,
                }
            };
        )

        let path = path.dir_path().join("METADATA.json");

        if !path.exists() {
            return;
        }

        let content = ok!(ok!(fs::File::open(&path)).read_to_string());

        match json::decode::<MetaData>(content.as_slice()) {
            Ok(metadata) => {
                if !metadata.name.is_empty() {
                    desc.name = Some(metadata.name);
                }
                if !metadata.designer.is_empty() {
                    desc.designer = Some(metadata.designer);
                }
            },
            Err(_) => {},
        }
    }

    fn populate_by_inference(desc: &mut Description, path: &Path) {
        if desc.name.is_some() {
            return;
        }

        match path.extension() {
            Some(b"ttf") | Some(b"TTF") => {},
            _ => return,
        }

        let path = path.with_extension("");
        let blob = match path.filename_str() {
            Some(blob) => blob,
            _ => return,
        };

        let blob = match blob.split('-').next() {
            Some(blob) => blob,
            _ => return,
        };

        let mut name = String::new();
        for (i, c) in blob.char_indices() {
            match c {
                'A'...'Z' if i > 0 => {
                    name.push(' ');
                    name.push(c);
                },
                _ => {
                    name.push(c);
                },
            }
        }

        if !name.is_empty() {
            desc.name = Some(name);
        }
    }

    fn populate_by_guessing(desc: &mut Description, _: &Path) {
        let chunks = match desc.name {
            Some(ref name) => name.as_slice().split(' ').collect::<Vec<_>>(),
            None => return,
        };

        for count in range(1, chunks.len() + 1).rev() {
            let mut name = String::new();
            for &chunk in chunks.iter().take(count) {
                if !name.is_empty() {
                    name.push('+');
                }
                name.push_str(chunk);
            }

            let url = format!("https://www.google.com/fonts/specimen/{}", name);
            if ping(url.as_slice()) {
                desc.url = Some(url);
                break;
            }
        }
    }
}

fn ping(url: &str) -> bool {
    use curl::http;
    match http::handle().head(url).exec() {
        Ok(response) => response.get_code() == 200,
        Err(_) => false,
    }
}
<|endoftext|>