<commit_before>use std::net::SocketAddr;
use std::sync::{ Arc, RwLock };
use std::thread::{ JoinHandle, spawn };
use ::config::ServerConfig;
use ::state::State;
use bytes::BytesMut;
use tokio::prelude::{ Async, AsyncRead, Future, Poll, Stream };
use tokio::net::{ TcpStream, TcpListener };
use tokio::io;

#[derive(Clone)]
pub struct Server {
    config: ServerConfig,
    state: Arc<RwLock<State>>
}

impl Server {
    pub fn new(config: ServerConfig, state: Arc<RwLock<State>>) -> Self {
        Self { config, state }
    }

    pub fn start(&mut self) {
        let addr = SocketAddr::new(self.config.listen_address, self.config.listen_port);

        if let Ok(listener) = TcpListener::bind(&addr) {
            let server = listener.incoming().for_each(move |socket| {
                println!("New connection: {:?}", socket.peer_addr().unwrap());

                let codec = ClientCodec::new(socket);

                let connection = codec.into_future()
                    .map_err(|_| ())
                    .map(|_| ());
/*
                let connection = TestFuture::new(socket).then(|_| {
                    println!("Accepted and stuff");
                    Ok(())
                }).map_err(|_| ());
                */

                ::tokio::spawn(connection);

                Ok(())
            }).map_err(|err| println!("Accept error: {:?}", err));

            ::tokio::run(server);
        } else {
            println!("Failed to bind to address: {:?}", addr);
        }
    }

    pub fn start_detached(&mut self) -> JoinHandle<()> {
        let mut self_clone = self.clone();

        spawn(move || {
            self_clone.start();
        })
    }

    pub fn stop(self, handle: JoinHandle<()>) {
        match handle.join() {
            Ok(h) => println!("Server stopped {:?}", h),
            Err(err) => println!("Error while joining {:?}", err)
        }
    }
}

struct ClientCodec {
    stream: TcpStream,
    read_buffer: BytesMut,
    write_buffer: BytesMut
}

impl ClientCodec {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            read_buffer: BytesMut::new(),
            write_buffer: BytesMut::new()
        }
    }

    fn read_next_packet(&mut self) -> Poll<(), io::Error> {
        loop {
            self.read_buffer.reserve(1024);

            let n = try_ready!(self.stream.read_buf(&mut self.read_buffer));

            println!("Got value from try_ready: {}", n);

            if n == 0 {
                return Ok(Async::Ready(()))
            }
        }
    }
}

impl Stream for ClientCodec {

    type Item = ClientMessage;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let sock_closed = self.read_next_packet()?.is_ready();

        println!("- read next {:?} {:?}", sock_closed, self.read_buffer.len());

        if self.read_buffer.len() >= 10 {
            let msg_code = self.read_buffer.split_to(2);

            match &msg_code[..] {
                b"he" => println!("Hello request"),
                _ => println!("Unknown package")

            }

            return Ok(Async::Ready(Some(ClientMessage::Noop)))
        }

        if sock_closed {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}

enum ClientMessage {
    Noop
}

/*
struct TestFuture {
    inner: Box<Future<Item=(), Error=()>>
}

impl TestFuture {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            inner: Box::new(io::write_all(stream, "HELLO\n").map(|_| ()).map_err(|_| ()))
        }
    }
}

impl Future for TestFuture {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        let v = try_ready!(self.inner.poll());
        Ok(Async::Ready(()))

        //try_ready!(self.inner.poll())
    }

}
*/

enum ClientState {
    NewConnection(TcpStream),
}

struct AcceptClient {
    state: ClientState,
}

impl AcceptClient {
    pub fn new(stream: TcpStream) -> AcceptClient {
        Self { state: ClientState::NewConnection(stream) }
    }
}

impl Future for AcceptClient {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        /*
        match self.state {
            ClientState::NewConnection(ref mut stream) => {
                let mut a = io::write_all(stream, "HELLO\n")
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "ACK\n") })
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "KTHXBYE\n") })
                .map(|_| ());

                a.poll()
            }
        }
        */

        match self.state {
            ClientState::NewConnection(ref mut stream) => {
                let mut a = io::write_all(stream, "HELLO\n")
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "ACK\n") })
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "KTHXBYE\n") })
                .map(|_| ());

                loop {
                    let v = match a.poll() {
                        Ok(Async::Ready(t)) => t,
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => return Err(err)
                    };

                    println!("Got result: {:?}", v);
                    break;
                };

                Ok(Async::Ready(()))
            }
        }
    }
}<commit_msg>Now the server is able to keep the connection alive<commit_after>use std::net::SocketAddr;
use std::sync::{ Arc, RwLock };
use std::thread::{ JoinHandle, spawn };
use bytes::BytesMut;
use futures::future;
use futures::future::Either;
use tokio::prelude::{ Async, AsyncRead, Future, Poll, Stream };
use tokio::net::{ TcpStream, TcpListener };
use tokio::io;
use ::config::ServerConfig;
use ::state::State;

#[derive(Clone)]
pub struct Server {
    config: ServerConfig,
    state: Arc<RwLock<State>>
}

impl Server {
    pub fn new(config: ServerConfig, state: Arc<RwLock<State>>) -> Self {
        Self { config, state }
    }

    pub fn start(&mut self) {
        let addr = SocketAddr::new(self.config.listen_address, self.config.listen_port);

        if let Ok(listener) = TcpListener::bind(&addr) {
            let server = listener.incoming().for_each(move |socket| {
                println!("New connection: {:?}", socket.peer_addr().unwrap());

                let codec = ClientCodec::new(socket);

                // ---------------------------------
                let connection = codec.into_future()
                    .map_err(|(e, _)| e)
                    .and_then(|(first_event, events)| {
                        println!("First event: {:?}", first_event);

                        match first_event {
                            None => return Either::A(future::ok(())),
                            _ => ()
                        }

                        let client = Client::new(events);

                        Either::B(client)
                    })
                    .map_err(|_| ());
/*
                let connection = TestFuture::new(socket).then(|_| {
                    println!("Accepted and stuff");
                    Ok(())
                }).map_err(|_| ());
                */

                ::tokio::spawn(connection);

                Ok(())
            }).map_err(|err| println!("Accept error: {:?}", err));

            ::tokio::run(server);
        } else {
            println!("Failed to bind to address: {:?}", addr);
        }
    }

    pub fn start_detached(&mut self) -> JoinHandle<()> {
        let mut self_clone = self.clone();

        spawn(move || {
            self_clone.start();
        })
    }

    pub fn stop(self, handle: JoinHandle<()>) {
        match handle.join() {
            Ok(h) => println!("Server stopped {:?}", h),
            Err(err) => println!("Error while joining {:?}", err)
        }
    }
}

struct ClientCodec {
    stream: TcpStream,
    read_buffer: BytesMut,
    write_buffer: BytesMut
}

impl ClientCodec {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            stream,
            read_buffer: BytesMut::new(),
            write_buffer: BytesMut::new()
        }
    }

    fn read_next_packet(&mut self) -> Poll<(), io::Error> {
        loop {
            self.read_buffer.reserve(1024);

            let n = try_ready!(self.stream.read_buf(&mut self.read_buffer));

            println!("Got value from try_ready: {}", n);

            if n == 0 {
                return Ok(Async::Ready(()))
            }
        }
    }
}

impl Stream for ClientCodec {

    type Item = ClientMessage;
    type Error = io::Error;

    fn poll(&mut self) -> Poll<Option<Self::Item>, Self::Error> {
        let sock_closed = self.read_next_packet()?.is_ready();

        println!("- read next {:?} {:?}", sock_closed, self.read_buffer.len());

        if self.read_buffer.len() >= 10 {
            let msg_code = self.read_buffer.split_to(2);

            match &msg_code[..] {
                b"he" => println!("Hello request"),
                _ => println!("Unknown package")

            }

            return Ok(Async::Ready(Some(ClientMessage::Noop)))
        }

        if sock_closed {
            Ok(Async::Ready(None))
        } else {
            Ok(Async::NotReady)
        }
    }
}

#[derive(Debug)]
enum ClientMessage {
    Noop
}

struct Client {
    codec: ClientCodec
}

impl Client {
    pub fn new(codec: ClientCodec) -> Self {
        Self { codec }
    }
}

impl Future for Client {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Poll<(), io::Error> {
        while let Async::Ready(event) = self.codec.poll()? {
            println!("Got some event: {:?}", event);

            if let Some(msg) = event {
                println!("Processing message: {:?}", msg);
            } else {
                println!("No more messages, client has disconnected");
                return Ok(Async::Ready(()))
            }
        }

        Ok(Async::NotReady)
    }
}
/*
struct TestFuture {
    inner: Box<Future<Item=(), Error=()>>
}

impl TestFuture {
    pub fn new(stream: TcpStream) -> Self {
        Self {
            inner: Box::new(io::write_all(stream, "HELLO\n").map(|_| ()).map_err(|_| ()))
        }
    }
}

impl Future for TestFuture {
    type Item = ();
    type Error = ();

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        let v = try_ready!(self.inner.poll());
        Ok(Async::Ready(()))

        //try_ready!(self.inner.poll())
    }

}
*/

enum ClientState {
    NewConnection(TcpStream),
}

struct AcceptClient {
    state: ClientState,
}

impl AcceptClient {
    pub fn new(stream: TcpStream) -> AcceptClient {
        Self { state: ClientState::NewConnection(stream) }
    }
}

impl Future for AcceptClient {
    type Item = ();
    type Error = io::Error;

    fn poll(&mut self) -> Result<Async<Self::Item>, Self::Error> {
        /*
        match self.state {
            ClientState::NewConnection(ref mut stream) => {
                let mut a = io::write_all(stream, "HELLO\n")
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "ACK\n") })
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "KTHXBYE\n") })
                .map(|_| ());

                a.poll()
            }
        }
        */

        match self.state {
            ClientState::NewConnection(ref mut stream) => {
                let mut a = io::write_all(stream, "HELLO\n")
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "ACK\n") })
                .and_then(|(s, b)| {
                    let buf = vec![0; 5];
                    io::read_exact(s, buf)
                })
                .and_then(|(s, b)| { io::write_all(s, "KTHXBYE\n") })
                .map(|_| ());

                loop {
                    let v = match a.poll() {
                        Ok(Async::Ready(t)) => t,
                        Ok(Async::NotReady) => return Ok(Async::NotReady),
                        Err(err) => return Err(err)
                    };

                    println!("Got result: {:?}", v);
                    break;
                };

                Ok(Async::Ready(()))
            }
        }
    }
}<|endoftext|>


<commit_before>//! Interval-based annotation features.

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{self, Display};

use bio::io::Strand;
use bio::utils::{Interval, IntervalError};

use self::error::FeatureError;

pub mod error {

    use super::*;

    #[derive(Debug, PartialEq)]
    pub enum FeatureError {
        IntervalError,
        StrandCharError,
    }

    impl Error for FeatureError {

        fn description(&self) -> &str {
            match *self {
                FeatureError::IntervalError => "interval start coordinate larger than its end coordinate",
                FeatureError::StrandCharError => "strand character is invalid",
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl Display for FeatureError {

        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }
}

trait Annotation {
    fn seq_name(&self) -> &str;
    fn interval(&self) -> &Interval<u64>;
    fn attributes(&self) -> &HashMap<String, String>;
    fn attribute(&self, key: &str) -> Option<&str>;
    fn strand(&self) -> &Strand;
}

macro_rules! impl_annotation {
    ($struct_ty:ty) => (

        impl Annotation for $struct_ty {

            fn seq_name(&self) -> &str {
                self.seq_name.as_str()
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn attributes(&self) -> &HashMap<String, String> {
                &self.attributes
            }

            fn attribute(&self, key: &str) -> Option<&str> {
                self.attributes.get(key).map(|n| n.as_str())
            }

            fn strand(&self) -> &Strand {
                &self.strand
            }
        }

    );
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TxFeature {
    Exon,
    UTR,
    UTR5,
    UTR3,
    CDS,
    StartCodon,
    StopCodon,
    Any,
}

#[derive(Debug)]
pub struct TranscriptFeature {
    kind: TxFeature,
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>
}

impl_annotation!(TranscriptFeature);

impl TranscriptFeature {

    fn kind(&self) -> &TxFeature {
        &self.kind
    }
}

pub struct TxFeatureBuilder {
    seq_name: String,
    start: u64,
    end: u64,
    strand: Strand,
    strand_char: Option<char>,
    attributes: HashMap<String, String>,
    kind: TxFeature,
}

impl TxFeatureBuilder {

    fn new<T>(seq_name: T, start: u64, end: u64) -> TxFeatureBuilder
        where T: Into<String>
    {
        TxFeatureBuilder {
            seq_name: seq_name.into(),
            start: start, end: end,
            kind: TxFeature::Any,
            strand: Strand::Unknown,
            attributes: HashMap::new(),
            strand_char: None,
        }
    }

    fn kind(mut self, kind: TxFeature) -> TxFeatureBuilder {
        self.kind = kind;
        self
    }

    fn strand(mut self, strand: Strand) -> TxFeatureBuilder {
        self.strand = strand;
        self
    }

    fn strand_char(mut self, strand_char: char) -> TxFeatureBuilder {
        self.strand_char = Some(strand_char);
        self
    }

    fn attribute<K, V>(mut self, key: K, value: V) -> TxFeatureBuilder
        where K: Into<String>, V: Into<String>
    {
        self.attributes.insert(key.into(), value.into());
        self
    }

    fn build(self) -> Result<TranscriptFeature, FeatureError> {
        let interval = Interval::new(self.start..self.end)
            .map_err(|err| match err {
                IntervalError::InvalidRange => FeatureError::IntervalError
            })?;

        let strand = match self.strand_char {
            None => Ok(self.strand),
            Some('+') | Some('f') => Ok(Strand::Forward),
            Some('-') | Some('r') => Ok(Strand::Reverse),
            Some('.') | Some('?') => Ok(Strand::Unknown),
            _         => Err(FeatureError::StrandCharError),
        }?;

        let feature = TranscriptFeature {
            seq_name: self.seq_name, kind: self.kind, interval: interval,
            strand: strand, attributes: self.attributes,
        };
        Ok(feature)
    }
}

#[derive(Debug)]
pub struct Transcript {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    features: Vec<TranscriptFeature>,
}

impl_annotation!(Transcript);

#[derive(Debug)]
pub struct Gene {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    transcripts: HashMap<String, Transcript>,
}

impl_annotation!(Gene);

#[cfg(test)]
mod test_transcript_feature {
    use super::*;

    #[test]
    fn test_builder() {
        let tfm1 = TxFeatureBuilder::new("chrT", 10, 20)
            .kind(TxFeature::Exon)
            .strand(Strand::Forward)
            .attribute("name", "ex1")
            .build();
        assert!(tfm1.is_ok());
        let tf = tfm1.unwrap();
        assert_eq!(tf.seq_name(), "chrT");
        assert_eq!(tf.kind(), &TxFeature::Exon);
        assert_eq!(tf.strand(), &Strand::Forward);
        assert_eq!(tf.attribute("name"), Some("ex1"));
        assert_eq!(tf.attributes.len(), 1);

        let tfm2 = TxFeatureBuilder::new("chrO", 10, 10)
            .build();
        assert!(tfm2.is_ok());
    }

    #[test]
    fn test_builder_strand_char() {
        let tfm = TxFeatureBuilder::new("chrT", 20, 30)
            .strand(Strand::Forward)
            .strand_char('-')
            .build();
        assert!(tfm.is_ok());
        let tf = tfm.unwrap();
        assert_eq!(tf.strand(), &Strand::Reverse);
    }

    #[test]
    fn test_builder_interval_err() {
        let tfm = TxFeatureBuilder::new("chrE", 20, 10).build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::IntervalError);
    }

    #[test]
    fn test_build_strand_char_err() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('w')
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::StrandCharError);
    }
}
<commit_msg>Implement multiple strand input types to builder<commit_after>//! Interval-based annotation features.

use std::error::Error;
use std::collections::HashMap;
use std::fmt::{self, Display};

use bio::io::Strand;
use bio::utils::{Interval, IntervalError};

use self::error::FeatureError;

pub mod error {

    use super::*;

    #[derive(Debug, PartialEq)]
    pub enum FeatureError {
        IntervalError,
        StrandCharError,
        ConflictingStrandError,
        UnspecifiedStrandError,
    }

    impl Error for FeatureError {

        fn description(&self) -> &str {
            match *self {
                FeatureError::IntervalError => "interval start coordinate larger than its end coordinate",
                FeatureError::StrandCharError => "strand character is invalid",
                FeatureError::ConflictingStrandError => "conflicting strand inputs specified",
                FeatureError::UnspecifiedStrandError => "strand not specified",
            }
        }

        fn cause(&self) -> Option<&Error> {
            None
        }
    }

    impl Display for FeatureError {

        fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
            write!(f, "FeatureError: {}", self.description())
        }
    }
}

trait Annotation {
    fn seq_name(&self) -> &str;
    fn interval(&self) -> &Interval<u64>;
    fn attributes(&self) -> &HashMap<String, String>;
    fn attribute(&self, key: &str) -> Option<&str>;
    fn strand(&self) -> &Strand;
}

macro_rules! impl_annotation {
    ($struct_ty:ty) => (

        impl Annotation for $struct_ty {

            fn seq_name(&self) -> &str {
                self.seq_name.as_str()
            }

            fn interval(&self) -> &Interval<u64> {
                &self.interval
            }

            fn attributes(&self) -> &HashMap<String, String> {
                &self.attributes
            }

            fn attribute(&self, key: &str) -> Option<&str> {
                self.attributes.get(key).map(|n| n.as_str())
            }

            fn strand(&self) -> &Strand {
                &self.strand
            }
        }

    );
}

fn char_to_strand(strand_char: char) -> Result<Strand, FeatureError> {
    match strand_char {
        '+' | 'f' | 'F' => Ok(Strand::Forward),
        '-' | 'r' | 'R' => Ok(Strand::Reverse),
        '.' | '?' => Ok(Strand::Unknown),
        _ => Err(FeatureError::StrandCharError),
    }
}

fn resolve_strand_input(strand: Option<Strand>, strand_char: Option<char>) -> Result<Strand, FeatureError> {
    match (strand, strand_char) {
        (None, None) => Err(FeatureError::UnspecifiedStrandError),
        (Some(sv), None) => Ok(sv),
        (None, Some(scv)) => char_to_strand(scv),
        (Some(sv), Some(scv)) => {
            let sv_from_char = char_to_strand(scv)?;
            if sv == sv_from_char {
                Ok(sv)
            } else {
                Err(FeatureError::ConflictingStrandError)
            }
        }
    }
}

fn coords_to_interval(start: u64, end: u64) -> Result<Interval<u64>, FeatureError> {
    Interval::new(start..end)
        .map_err(|err| match err {
            IntervalError::InvalidRange => FeatureError::IntervalError
        })
}

#[derive(Debug, Clone, Copy, PartialEq)]
pub enum TxFeature {
    Exon,
    UTR,
    UTR5,
    UTR3,
    CDS,
    StartCodon,
    StopCodon,
    Any,
}

#[derive(Debug)]
pub struct TranscriptFeature {
    kind: TxFeature,
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>
}

impl_annotation!(TranscriptFeature);

impl TranscriptFeature {

    fn kind(&self) -> &TxFeature {
        &self.kind
    }
}

pub struct TxFeatureBuilder {
    seq_name: String,
    start: u64,
    end: u64,
    attributes: HashMap<String, String>,
    kind: TxFeature,
    strand: Option<Strand>,
    strand_char: Option<char>,
}

impl TxFeatureBuilder {

    fn new<T>(seq_name: T, start: u64, end: u64) -> TxFeatureBuilder
        where T: Into<String>
    {
        TxFeatureBuilder {
            seq_name: seq_name.into(),
            start: start, end: end,
            kind: TxFeature::Any,
            attributes: HashMap::new(),
            strand: None,
            strand_char: None,
        }
    }

    fn kind(mut self, kind: TxFeature) -> TxFeatureBuilder {
        self.kind = kind;
        self
    }

    fn strand(mut self, strand: Strand) -> TxFeatureBuilder {
        self.strand = Some(strand);
        self
    }

    fn strand_char(mut self, strand_char: char) -> TxFeatureBuilder {
        self.strand_char = Some(strand_char);
        self
    }

    fn attribute<K, V>(mut self, key: K, value: V) -> TxFeatureBuilder
        where K: Into<String>, V: Into<String>
    {
        self.attributes.insert(key.into(), value.into());
        self
    }

    fn build(self) -> Result<TranscriptFeature, FeatureError> {
        let interval = coords_to_interval(self.start, self.end)?;
        let strand = resolve_strand_input(self.strand, self.strand_char)?;
        let feature = TranscriptFeature {
            seq_name: self.seq_name, kind: self.kind, interval: interval,
            strand: strand, attributes: self.attributes,
        };
        Ok(feature)
    }
}

#[derive(Debug)]
pub struct Transcript {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    features: Vec<TranscriptFeature>,
}

impl_annotation!(Transcript);

#[derive(Debug)]
pub struct Gene {
    seq_name: String,
    interval: Interval<u64>,
    strand: Strand,
    attributes: HashMap<String, String>,
    transcripts: HashMap<String, Transcript>,
}

impl_annotation!(Gene);

#[cfg(test)]
mod test_transcript_feature {
    use super::*;

    #[test]
    fn test_builder() {
        let tfm1 = TxFeatureBuilder::new("chrT", 10, 20)
            .kind(TxFeature::Exon)
            .strand(Strand::Forward)
            .attribute("name", "ex1")
            .build();
        assert!(tfm1.is_ok());
        let tf = tfm1.unwrap();
        assert_eq!(tf.seq_name(), "chrT");
        assert_eq!(tf.kind(), &TxFeature::Exon);
        assert_eq!(tf.strand(), &Strand::Forward);
        assert_eq!(tf.attribute("name"), Some("ex1"));
        assert_eq!(tf.attributes.len(), 1);

        let tfm2 = TxFeatureBuilder::new("chrO", 10, 10)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm2.is_ok());
    }

    #[test]
    fn test_builder_interval_invalid() {
        let tfm = TxFeatureBuilder::new("chrE", 20, 10).build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::IntervalError);
    }

    #[test]
    fn test_builder_strand_unspecified() {
        let tfm = TxFeatureBuilder::new("chrT", 20, 30)
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::UnspecifiedStrandError);
    }

    #[test]
    fn test_build_strand_char_unexpected() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('w')
            .build();
        assert!(tfm.is_err());
        assert_eq!(tfm.unwrap_err(), FeatureError::StrandCharError);
    }

    #[test]
    fn test_build_strand_char_conflicting() {
        let tfm = TxFeatureBuilder::new("chrE", 10, 20)
            .strand_char('-')
            .strand(Strand::Reverse)
            .build();
        assert!(tfm.is_ok());
        let tf = tfm.unwrap();
        assert_eq!(tf.strand(), &Strand::Reverse);
    }
}
<|endoftext|>


<commit_before>const MONTHS_TO_YEAR: i32 = 12;
const MICROS_TO_HOUR: i64 = 3600000000;
const MICROS_TO_MINUTE: i64 = 60000000;
const MICROS_TO_SECOND: i64 = 1000000;

pub fn get_year_month_interval(months: i32) -> (i32, i8) {
    let years: i32 = months/MONTHS_TO_YEAR;
    let months: i8 = (months - (years * MONTHS_TO_YEAR)) as i8;
    (years, months)
}

pub fn get_day_time_interval(microseconds: i64) -> (i64, i8, f64) {
    let hours: i64 = microseconds/MICROS_TO_HOUR;
    let current_hours: i64 = hours * MICROS_TO_HOUR;
    let minutes: i64 = (microseconds - current_hours)/MICROS_TO_MINUTE;
    let seconds: f64 = (microseconds - (current_hours+(minutes * MICROS_TO_MINUTE))) as f64/MICROS_TO_SECOND as f64;
    (hours, minutes as i8, seconds)
}
<commit_msg>test(helpers): add tests for deriving the year month interval and day time interval<commit_after>const MONTHS_TO_YEAR: i32 = 12;
const MICROS_TO_HOUR: i64 = 3600000000;
const MICROS_TO_MINUTE: i64 = 60000000;
const MICROS_TO_SECOND: i64 = 1000000;

pub fn get_year_month_interval(months: i32) -> (i32, i8) {
    let years: i32 = months/MONTHS_TO_YEAR;
    let months: i8 = (months - (years * MONTHS_TO_YEAR)) as i8;
    (years, months)
}

pub fn get_day_time_interval(microseconds: i64) -> (i64, i8, f64) {
    let hours: i64 = microseconds/MICROS_TO_HOUR;
    let current_hours: i64 = hours * MICROS_TO_HOUR;
    let minutes: i64 = (microseconds - current_hours)/MICROS_TO_MINUTE;
    let seconds: f64 = (microseconds - (current_hours+(minutes * MICROS_TO_MINUTE))) as f64/MICROS_TO_SECOND as f64;
    (hours, minutes as i8, seconds)
}

#[cfg(test)]
mod tests {
    use super::*;
    #[test]
    fn negative_year_month_interval() {
        let months = i32::min_value();
        let (years, months) = get_year_month_interval(months);
        assert!(years == -178956970);
        assert!(months == -8);
    }

    #[test]
    fn positive_year_month_interval() {
        let months = i32::max_value();
        let (years, months) = get_year_month_interval(months);
        assert!(years == 178956970);
        assert!(months == 7);
    }

    #[test]
    fn negative_day_time_interval() {
        let microseconds = -7199000000;
        let (hours, minutes, seconds) = get_day_time_interval(microseconds);
        assert!(hours == -1);
        assert!(minutes == -59);
        assert!(seconds == -59.0);
    }

    #[test]
    fn postive_day_time_interval() {
        let microseconds = 7199000000;
        let (hours, minutes, seconds) = get_day_time_interval(microseconds);
        assert!(hours == 1);
        assert!(minutes == 59);
        assert!(seconds == 59.0);
    }

    #[test]
    fn day_time_remaining_milliseconds() {
        let microseconds = 7199001000;
        let (hours, minutes, seconds) = get_day_time_interval(microseconds);
        assert!(hours == 1);
        assert!(minutes == 59);
        assert!(seconds == 59.001);
    }

    #[test]
    fn day_time_remaining_millisecond() {
        let microseconds = 7199000001;
        let (hours, minutes, seconds) = get_day_time_interval(microseconds);
        assert!(hours == 1);
        assert!(minutes == 59);
        assert!(seconds == 59.000001);
    }
}
<|endoftext|>


<commit_before>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns 0.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// helpers::bpf_trace_printf(1, 15, 32, 0, 0);
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code produced would be nearly the same as when compiling the following code from C to
/// eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     char *fmt = "bpf_trace_printk %lx %lx %lx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    0
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<commit_msg>src/helpers.rs: fix documentation and example for `bpf_trace_printf()`<commit_after>// Copyright 2015 Big Switch Networks, Inc
//      (Algorithms for uBPF helpers, originally in C)
// Copyright 2016 6WIND S.A. <quentin.monnet@6wind.com>
//      (Translation to Rust, other helpers)
//
// Licensed under the Apache License, Version 2.0 <http://www.apache.org/licenses/LICENSE-2.0> or
// the MIT license <http://opensource.org/licenses/MIT>, at your option. This file may not be
// copied, modified, or distributed except according to those terms.

//! This module implements some built-in helpers that can be called from within an eBPF program.
//!
//! These helpers may originate from several places:
//!
//! * Some of them mimic the helpers available in the Linux kernel.
//! * Some of them were proposed as example helpers in uBPF and they were adapted here.
//! * Other helpers may be specific to rbpf.
//!
//! The prototype for helpers is always the same: five `u64` as arguments, and a `u64` as a return
//! value. Hence some helpers have unused arguments, or return a 0 value in all cases, in order to
//! respect this convention.

use std::u64;

// Helpers associated to kernel helpers
// See also linux/include/uapi/linux/bpf.h in Linux kernel sources.

// bpf_trace_printk()

/// Index of helper `bpf_trace_printk()`, equivalent to `bpf_trace_printf()`, in Linux kernel, see
/// <https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/tree/include/uapi/linux/bpf.h>.
pub const BPF_TRACE_PRINTK_IDX: u32 = 6;

/// Prints its **last three** arguments to standard output. The **first two** arguments are
/// **unused**. Returns 0.
///
/// By ignoring the first two arguments, it creates a helper that will have a behavior similar to
/// the one of the equivalent helper `bpf_trace_printk()` from Linux kernel.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// helpers::bpf_trace_printf(0, 0, 1, 15, 32);
/// ```
///
/// This will print `bpf_trace_printf: 0x1, 0xf, 0x20`.
///
/// The eBPF code needed to perform the call in this example would be nearly identical to the code
/// obtained by compiling the following code from C to eBPF with clang:
///
/// ```c
/// #include <linux/bpf.h>
/// #include "path/to/linux/samples/bpf/bpf_helpers.h"
///
/// int main(struct __sk_buff *skb)
/// {
///     char *fmt = "bpf_trace_printk %lx %lx %lx\n";
///     return bpf_trace_printk(fmt, sizeof(fmt), 1, 15, 32);
/// }
/// ```
///
/// This would equally print the three numbers in `/sys/kernel/debug/tracing` file each time the
/// program is run.
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn bpf_trace_printf (unused1: u64, unused2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    println!("bpf_trace_printf: {:#x}, {:#x}, {:#x}", arg3, arg4, arg5);
    0
}

// Helpers coming from uBPF <https://github.com/iovisor/ubpf/blob/master/vm/test.c>

/// The idea is to assemble five bytes into a single `u64`. For compatibility with the helpers API,
/// each argument must be a `u64`.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let gathered = helpers::gather_bytes(0x11, 0x22, 0x33, 0x44, 0x55);
/// assert_eq!(gathered, 0x1122334455);
/// ```
pub fn gather_bytes (arg1: u64, arg2: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
    arg1.wrapping_shl(32) |
    arg2.wrapping_shl(24) |
    arg3.wrapping_shl(16) |
    arg4.wrapping_shl(8)  |
    arg5
}

/// Same as `void *memfrob(void *s, size_t n);` in `string.h` in C. See the GNU manual page (in
/// section 3) for `memfrob`. The memory is directly modified, and the helper returns 0 in all
/// cases. Arguments 3 to 5 are unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let val: u64 = 0x112233;
/// let val_ptr = &val as *const u64;
///
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x2a2a2a2a2a3b0819);
/// helpers::memfrob(val_ptr as u64, 8, 0, 0, 0);
/// assert_eq!(val, 0x112233);
/// ```
#[allow(unused_variables)]
pub fn memfrob (ptr: u64, len: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    for i in 0..len {
        unsafe {
            let mut p = (ptr + i) as *mut u8;
            *p ^= 0b101010;
        }
    }
    0
}

// TODO: Try again when asm!() is available in stable Rust.
// #![feature(asm)]
// #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
// #[allow(unused_variables)]
// pub fn memfrob (ptr: u64, len: u64, arg3: u64, arg4: u64, arg5: u64) -> u64 {
//     unsafe {
//         asm!(
//                 "mov $0xf0, %rax"
//             ::: "mov $0xf1, %rcx"
//             ::: "mov $0xf2, %rdx"
//             ::: "mov $0xf3, %rsi"
//             ::: "mov $0xf4, %rdi"
//             ::: "mov $0xf5, %r8"
//             ::: "mov $0xf6, %r9"
//             ::: "mov $0xf7, %r10"
//             ::: "mov $0xf8, %r11"
//         );
//     }
//     0
// }

/// Compute and return the square root of argument 1, cast as a float. Arguments 2 to 5 are
/// unused.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let x = helpers::sqrti(9, 0, 0, 0, 0);
/// assert_eq!(x, 3);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn sqrti (arg1: u64, unused2: u64, unused3: u64, unused4: u64, unused5: u64) -> u64 {
    (arg1 as f64).sqrt() as u64
}

/// C-like `strcmp`, return 0 if the strings are equal, and a non-null value otherwise.
///
/// # Examples
///
/// ```
/// use rbpf::helpers;
///
/// let foo = "This is a string.".as_ptr() as u64;
/// let bar = "This is another sting.".as_ptr() as u64;
///
/// assert!(helpers::strcmp(foo, foo, 0, 0, 0) == 0);
/// assert!(helpers::strcmp(foo, bar, 0, 0, 0) != 0);
/// ```
#[allow(dead_code)]
#[allow(unused_variables)]
pub fn strcmp (arg1: u64, arg2: u64, arg3: u64, unused4: u64, unused5: u64) -> u64 {
    // C-like strcmp, maybe shorter than converting the bytes to string and comparing?
    if arg1 == 0 || arg2 == 0 {
        return u64::MAX;
    }
    let mut a = arg1;
    let mut b = arg2;
    unsafe {
        let mut a_val = *(a as *const u8);
        let mut b_val = *(b as *const u8);
        while a_val == b_val && a_val != 0 && b_val != 0 {
            a +=1 ;
            b +=1 ;
            a_val = *(a as *const u8);
            b_val = *(b as *const u8);
        }
        if a_val >= b_val {
            (a_val - b_val) as u64
        } else {
            (b_val - a_val) as u64
        }
    }
}
<|endoftext|>


<commit_before>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        // TODO umask
        let file = try!(File::create(path));
        if cfg!(unix) {
            use libc;
            use std::os::unix::io::AsRawFd;
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<commit_msg>Fix insecure history file creation.<commit_after>//! History API

use std::collections::VecDeque;
use std::collections::vec_deque;
use std::fs::File;
use std::iter::DoubleEndedIterator;
use std::ops::Index;
use std::path::Path;
#[cfg(unix)]
use libc;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;

use super::Result;
use config::{Config, HistoryDuplicates};

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Direction {
    Forward,
    Reverse,
}

/// Current state of the history.
pub struct History {
    entries: VecDeque<String>,
    max_len: usize,
    ignore_space: bool,
    ignore_dups: bool,
}

impl History {
    pub fn new(config: Config) -> History {
        History {
            entries: VecDeque::new(),
            max_len: config.max_history_size(),
            ignore_space: config.history_duplicates() == HistoryDuplicates::IgnoreConsecutive,
            ignore_dups: config.history_ignore_space(),
        }
    }

    /// Return the history entry at position `index`, starting from 0.
    pub fn get(&self, index: usize) -> Option<&String> {
        self.entries.get(index)
    }

    /// Return the last history entry (i.e. previous command)
    pub fn last(&self) -> Option<&String> {
        self.entries.back()
    }

    /// Add a new entry in the history.
    pub fn add<S: AsRef<str> + Into<String>>(&mut self, line: S) -> bool {
        if self.max_len == 0 {
            return false;
        }
        if line.as_ref().is_empty() ||
           (self.ignore_space && line.as_ref().chars().next().map_or(true, |c| c.is_whitespace())) {
            return false;
        }
        if self.ignore_dups {
            if let Some(s) = self.entries.back() {
                if s == line.as_ref() {
                    return false;
                }
            }
        }
        if self.entries.len() == self.max_len {
            self.entries.pop_front();
        }
        self.entries.push_back(line.into());
        true
    }

    /// Returns the number of entries in the history.
    pub fn len(&self) -> usize {
        self.entries.len()
    }
    /// Returns true if the history has no entry.
    pub fn is_empty(&self) -> bool {
        self.entries.is_empty()
    }

    /// Set the maximum length for the history. This function can be called even
    /// if there is already some history, the function will make sure to retain
    /// just the latest `len` elements if the new history length value is smaller
    /// than the amount of items already inside the history.
    pub fn set_max_len(&mut self, len: usize) {
        self.max_len = len;
        if len == 0 {
            self.entries.clear();
            return;
        }
        loop {
            if self.entries.len() <= len {
                break;
            }
            self.entries.pop_front();
        }
    }

    /// Save the history in the specified file.
    /// TODO append_history http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX30
    /// TODO history_truncate_file http://cnswww.cns.cwru.edu/php/chet/readline/history.html#IDX31
    pub fn save<P: AsRef<Path> + ?Sized>(&self, path: &P) -> Result<()> {
        use std::io::{BufWriter, Write};

        if self.is_empty() {
            return Ok(());
        }
        let old_umask = if cfg!(unix) {
            unsafe { libc::umask(libc::S_IXUSR | libc::S_IRWXG | libc::S_IRWXO) }
        } else {
            0
        };
        let f = File::create(path);
        if cfg!(unix) {
            unsafe {
                libc::umask(old_umask);
            }
        }
        let file = try!(f);
        if cfg!(unix) {
            unsafe {
                libc::fchmod(file.as_raw_fd(), libc::S_IRUSR | libc::S_IWUSR);
            }
        }
        let mut wtr = BufWriter::new(file);
        for entry in &self.entries {
            try!(wtr.write_all(&entry.as_bytes()));
            try!(wtr.write_all(b"\n"));
        }
        Ok(())
    }

    /// Load the history from the specified file.
    ///
    /// # Failure
    /// Will return `Err` if path does not already exist.
    pub fn load<P: AsRef<Path> + ?Sized>(&mut self, path: &P) -> Result<()> {
        use std::io::{BufRead, BufReader};

        let file = try!(File::open(&path));
        let rdr = BufReader::new(file);
        for line in rdr.lines() {
            self.add(try!(line).as_ref()); // TODO truncate to MAX_LINE
        }
        Ok(())
    }

    /// Clear history
    pub fn clear(&mut self) {
        self.entries.clear()
    }

    /// Search history (start position inclusive [0, len-1]).
    /// Return the absolute index of the nearest history entry that matches `term`.
    /// Return None if no entry contains `term` between [start, len -1] for forward search
    /// or between [0, start] for reverse search.
    pub fn search(&self, term: &str, start: usize, dir: Direction) -> Option<usize> {
        if term.is_empty() || start >= self.len() {
            return None;
        }
        match dir {
            Direction::Reverse => {
                let index = self.entries
                    .iter()
                    .rev()
                    .skip(self.entries.len() - 1 - start)
                    .position(|entry| entry.contains(term));
                index.and_then(|index| Some(start - index))
            }
            Direction::Forward => {
                let index = self.entries.iter().skip(start).position(|entry| entry.contains(term));
                index.and_then(|index| Some(index + start))
            }
        }
    }

    /// Return a forward iterator.
    pub fn iter(&self) -> Iter {
        Iter(self.entries.iter())
    }
}

impl Index<usize> for History {
    type Output = String;

    fn index(&self, index: usize) -> &String {
        &self.entries[index]
    }
}

impl<'a> IntoIterator for &'a History {
    type Item = &'a String;
    type IntoIter = Iter<'a>;

    fn into_iter(self) -> Iter<'a> {
        self.iter()
    }
}

/// History iterator.
pub struct Iter<'a>(vec_deque::Iter<'a, String>);

impl<'a> Iterator for Iter<'a> {
    type Item = &'a String;

    fn next(&mut self) -> Option<&'a String> {
        self.0.next()
    }

    fn size_hint(&self) -> (usize, Option<usize>) {
        self.0.size_hint()
    }
}

impl<'a> DoubleEndedIterator for Iter<'a> {
    fn next_back(&mut self) -> Option<&'a String> {
        self.0.next_back()
    }
}

#[cfg(test)]
mod tests {
    extern crate tempdir;
    use std::path::Path;
    use config::Config;
    use super::{Direction, History};

    fn init() -> History {
        let mut history = History::new(Config::default());
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(history.add("line3"));
        history
    }

    #[test]
    fn new() {
        let config = Config::default();
        let history = History::new(config);
        assert_eq!(config.max_history_size(), history.max_len);
        assert_eq!(0, history.entries.len());
    }

    #[test]
    fn add() {
        let config = Config::builder()
            .history_ignore_space(true)
            .build();
        let mut history = History::new(config);
        assert!(history.add("line1"));
        assert!(history.add("line2"));
        assert!(!history.add("line2"));
        assert!(!history.add(""));
        assert!(!history.add(" line3"));
    }

    #[test]
    fn set_max_len() {
        let mut history = init();
        history.set_max_len(1);
        assert_eq!(1, history.entries.len());
        assert_eq!(Some(&"line3".to_string()), history.last());
    }

    #[test]
    fn save() {
        let mut history = init();
        let td = tempdir::TempDir::new_in(&Path::new("."), "histo").unwrap();
        let history_path = td.path().join(".history");

        history.save(&history_path).unwrap();
        history.load(&history_path).unwrap();
        td.close().unwrap();
    }

    #[test]
    fn search() {
        let history = init();
        assert_eq!(None, history.search("", 0, Direction::Forward));
        assert_eq!(None, history.search("none", 0, Direction::Forward));
        assert_eq!(None, history.search("line", 3, Direction::Forward));

        assert_eq!(Some(0), history.search("line", 0, Direction::Forward));
        assert_eq!(Some(1), history.search("line", 1, Direction::Forward));
        assert_eq!(Some(2), history.search("line3", 1, Direction::Forward));
    }

    #[test]
    fn reverse_search() {
        let history = init();
        assert_eq!(None, history.search("", 2, Direction::Reverse));
        assert_eq!(None, history.search("none", 2, Direction::Reverse));
        assert_eq!(None, history.search("line", 3, Direction::Reverse));

        assert_eq!(Some(2), history.search("line", 2, Direction::Reverse));
        assert_eq!(Some(1), history.search("line", 1, Direction::Reverse));
        assert_eq!(Some(0), history.search("line1", 1, Direction::Reverse));
    }
}
<|endoftext|>


<commit_before>
extern crate irc;
use self::irc::client::prelude::*;
use markov_words::WordsDb;

pub struct BazIrc {
    words: WordsDb,
    server: IrcServer
}

impl BazIrc {
    pub fn new(words: WordsDb, server: IrcServer) -> BazIrc {
        BazIrc {
            words: words,
            server: server
        }
    }

    pub fn new_from_config(words: WordsDb, config: &str) -> BazIrc {
        let server = IrcServer::new(config).unwrap();
        BazIrc {
            words: words,
            server: server
        }
    }
    pub fn new_from_env(words: WordsDb) -> BazIrc {
        unimplemented!();
    }
    pub fn run(&self) {
        unimplemented!();
    }
}
<commit_msg>connect to irc<commit_after>
extern crate irc;
use self::irc::client::prelude::*;
use markov_words::WordsDb;

pub struct BazIrc {
    words: WordsDb,
    server: IrcServer
}

impl BazIrc {
    pub fn new(words: WordsDb, server: IrcServer) -> BazIrc {
        BazIrc {
            words: words,
            server: server
        }
    }

    pub fn new_from_config(words: WordsDb, config: &str) -> BazIrc {
        let server = IrcServer::new(config).unwrap();
        BazIrc {
            words: words,
            server: server
        }
    }
    pub fn new_from_env(words: WordsDb) -> BazIrc {
        unimplemented!();
    }
    pub fn run(&self) {
        let id = self.server.identify().unwrap();
        println!("id: {:?}", id);
        for message in self.server.iter() {
            println!("Message: {:?}", message);
        }
    }
}
<|endoftext|>


<commit_before>use transaction::{ Transaction, ModifierTransaction, PeriodicTransaction };
use amount::Amount;
use commodity::Commodity;
use chrono::{ Date, Local };

#[derive(Clone, PartialEq, Eq)]
pub struct MarketPrice {
    pub date: Date<Local>,
    pub commodity: Commodity,
    pub amount: Amount
}

#[derive(Clone, PartialEq, Eq)]
pub struct Year(usize);

#[derive(Clone, PartialEq, Eq)]
pub struct JournalContext {
    year: Option<Year>,
}

#[derive(Clone, PartialEq, Eq)]
pub struct Journal {
    pub modifier_transactions: Vec<ModifierTransaction>,
    pub periodic_transactions: Vec<PeriodicTransaction>,
    pub transactions: Vec<Transaction>,
    //pub open_timelog_entries: Vec<TimeLogEntry>,
    pub market_prices: Vec<MarketPrice>,
    pub final_comment_lines: String,
    pub context: JournalContext,
}
<commit_msg>adds new methods to the journal<commit_after>use transaction::{ Transaction, ModifierTransaction, PeriodicTransaction };
use amount::Amount;
use commodity::Commodity;
use chrono::{ Date, Local };
use posting::Posting;

#[derive(Clone, PartialEq, Eq)]
pub struct MarketPrice {
    pub date: Date<Local>,
    pub commodity: Commodity,
    pub amount: Amount
}

#[derive(Clone, PartialEq, Eq)]
pub struct Year(usize);

#[derive(Clone, PartialEq, Eq)]
pub struct JournalContext {
    year: Option<Year>,
}

impl JournalContext {
    pub fn new() -> JournalContext {
        JournalContext {
            year: None
        }
    }
}

/// Represents the complete journal
#[derive(Clone, PartialEq, Eq)]
pub struct Journal {
    pub modifier_transactions: Vec<ModifierTransaction>,
    pub periodic_transactions: Vec<PeriodicTransaction>,
    pub transactions: Vec<Transaction>,
    //pub open_timelog_entries: Vec<TimeLogEntry>,
    pub market_prices: Vec<MarketPrice>,
    pub final_comment_lines: String,
    pub context: JournalContext,
}

impl Journal {
    /// Adds a new transaction to the journal
    pub fn add_transaction_mut(&mut self, transaction: Transaction) {
        self.transactions.push(transaction)
    }

    /// Adds a new transaction to the journal and returns a copy
    pub fn add_transaction(&self, transaction: Transaction) -> Journal {
        self.add_item(|s, x| s.add_transaction_mut(x), transaction)
    }

    /// Adds a new modifier transaction to the journal
    pub fn add_modifier_transaction_mut(&mut self, modifier_transaction: ModifierTransaction) {
        self.modifier_transactions.push(modifier_transaction);
    }

    /// Adds a new modifier transaction to the journal and returns a copy
    pub fn add_modifier_transaction(&mut self, modifier_transaction: ModifierTransaction) -> Journal {
        self.add_item(|s, x| s.add_modifier_transaction_mut(x), modifier_transaction)
    }

    /// Adds a new market price to the journal
    pub fn add_market_price_mut(&mut self, market_price: MarketPrice) {
        self.market_prices.push(market_price);
    }

    /// Adds a new market price to the journal and returns a copy
    pub fn add_market_price(&self, market_price: MarketPrice) -> Journal {
        self.add_item(|s, x| s.add_market_price_mut(x), market_price)
    }

    /// Applies the given function to the journal to adds new items
    pub fn add_item<T, F>(&self, f: F, item: T) -> Journal where F : FnOnce(&mut Journal, T) {
        let mut x = self.clone();
        f(&mut x, item);
        x
    }

    /// Returns the transaction at the given index, if it is available
    pub fn transaction_at(&self, pos: usize) -> Option<&Transaction> {
        self.transactions.get(pos)
    }

    ///
    pub fn next_transaction(&self, transaction: &Transaction) -> Option<&Transaction> {
        self.transaction_at(transaction.index)
    }

    /// Collects all postings from all transactions and flattens it into a list
    pub fn postings(&self) -> Vec<Posting> {
        self.transactions.iter().flat_map(|x| x.postings.iter()).map(|x| x.clone()).collect()
    }
}
<|endoftext|>


<commit_before>/*
Module: sys

Misc low level stuff
*/
tag type_desc {
    type_desc(@type_desc);
}

#[abi = "cdecl"]
native mod rustrt {
    // Explicitly re-export native stuff we want to be made
    // available outside this crate. Otherwise it's
    // visible-in-crate, but not re-exported.
    fn last_os_error() -> str;
    fn size_of(td: *type_desc) -> uint;
    fn align_of(td: *type_desc) -> uint;
    fn refcount<T>(t: @T) -> uint;
    fn do_gc();
    fn unsupervise();
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn get_type_desc<T>() -> *type_desc;
}

/*
Function: get_type_desc

Returns a pointer to a type descriptor. Useful for calling certain
function in the Rust runtime or otherwise performing dark magick.
*/
fn get_type_desc<T>() -> *type_desc {
    ret rusti::get_type_desc::<T>();
}

/*
Function: last_os_error

Get a string representing the platform-dependent last error
*/
fn last_os_error() -> str {
    ret rustrt::last_os_error();
}

/*
Function: size_of

Returns the size of a type
*/
fn size_of<T>() -> uint {
    ret rustrt::size_of(get_type_desc::<T>());
}

/*
Function: align_of

Returns the alignment of a type
*/
fn align_of<T>() -> uint {
    ret rustrt::align_of(get_type_desc::<T>());
}

/*
Function: refcount

Returns the refcount of a shared box
*/
fn refcount<T>(t: @T) -> uint {
    ret rustrt::refcount::<T>(t);
}

/*
Function: do_gc

Force a garbage collection
*/
fn do_gc() -> () {
    ret rustrt::do_gc();
}

// FIXME: There's a wrapper for this in the task module and this really
// just belongs there
fn unsupervise() -> () {
    ret rustrt::unsupervise();
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<commit_msg>stdlib: Add some useful fields to the definition of type_desc<commit_after>/*
Module: sys

Misc low level stuff
*/
tag type_desc = {
    first_param: **ctypes::c_int,
    size: ctypes::size_t,
    align: ctypes::size_t
    // Remaining fields not listed
};

#[abi = "cdecl"]
native mod rustrt {
    // Explicitly re-export native stuff we want to be made
    // available outside this crate. Otherwise it's
    // visible-in-crate, but not re-exported.
    fn last_os_error() -> str;
    fn size_of(td: *type_desc) -> uint;
    fn align_of(td: *type_desc) -> uint;
    fn refcount<T>(t: @T) -> uint;
    fn do_gc();
    fn unsupervise();
}

#[abi = "rust-intrinsic"]
native mod rusti {
    fn get_type_desc<T>() -> *type_desc;
}

/*
Function: get_type_desc

Returns a pointer to a type descriptor. Useful for calling certain
function in the Rust runtime or otherwise performing dark magick.
*/
fn get_type_desc<T>() -> *type_desc {
    ret rusti::get_type_desc::<T>();
}

/*
Function: last_os_error

Get a string representing the platform-dependent last error
*/
fn last_os_error() -> str {
    ret rustrt::last_os_error();
}

/*
Function: size_of

Returns the size of a type
*/
fn size_of<T>() -> uint {
    ret rustrt::size_of(get_type_desc::<T>());
}

/*
Function: align_of

Returns the alignment of a type
*/
fn align_of<T>() -> uint {
    ret rustrt::align_of(get_type_desc::<T>());
}

/*
Function: refcount

Returns the refcount of a shared box
*/
fn refcount<T>(t: @T) -> uint {
    ret rustrt::refcount::<T>(t);
}

/*
Function: do_gc

Force a garbage collection
*/
fn do_gc() -> () {
    ret rustrt::do_gc();
}

// FIXME: There's a wrapper for this in the task module and this really
// just belongs there
fn unsupervise() -> () {
    ret rustrt::unsupervise();
}

// Local Variables:
// mode: rust;
// fill-column: 78;
// indent-tabs-mode: nil
// c-basic-offset: 4
// buffer-file-coding-system: utf-8-unix
// End:
<|endoftext|>


<commit_before>use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Logger, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::init_config;
use log::LogLevelFilter;

const WNI_MOD_PATH: &'static str = "tina::source::wni_client";
const EEW_MOD_PATH: &'static str = "tina::destination::logging_wrapper";
const TINA_ROOT_MOD_PATH: &'static str = "tina";
const FORMAT: &'static str = "[{d(%Y/%m/%d-%H:%M:%S)(utc)}][{l}\\({f}\\)] {m}{n}";

pub struct LogConfig {
	pub wni_log_path: Option<String>,
	pub wni_log_console: bool,
	pub eew_log_path: Option<String>,
	pub eew_log_console: bool,
	pub main_log_level: LogLevelFilter
}

fn register_inspection_point(file_path: Option<String>, to_root: bool, mod_path: String,
	level: LogLevelFilter, appenders: &mut Vec<Appender>, loggers: &mut Vec<Logger>)
	-> Result<(), ()>
{
	if let Some(path) = file_path {

		let name = mod_path.clone();
		let encoder = Box::new(PatternEncoder::new(FORMAT));
		let recorder = try!(FileAppender::builder().encoder(encoder).build(path).map_err(|_| ()));
		let appender = Appender::builder().build(name.clone(), Box::new(recorder));
		let logger = Logger::builder().appender(name).additive(to_root).build(mod_path, level);
		appenders.push(appender);
		loggers.push(logger);

	} else if !to_root {

		let logger = Logger::builder().additive(false).build(mod_path, LogLevelFilter::Off);
		loggers.push(logger);
	}

	Ok(())
}

pub fn setup_logging(conf: LogConfig) -> Result<(), ()>
{
	let mut appenders = Vec::new();
	let mut loggers = Vec::new();

	try!(register_inspection_point(conf.wni_log_path, conf.wni_log_console,
		WNI_MOD_PATH.to_string(), LogLevelFilter::Debug, &mut appenders, &mut loggers));
	try!(register_inspection_point(conf.eew_log_path, conf.eew_log_console,
		EEW_MOD_PATH.to_string(), LogLevelFilter::Info, &mut appenders, &mut loggers));

	let con_encoder = Box::new(PatternEncoder::new(FORMAT));
	let con_recorder = ConsoleAppender::builder().encoder(con_encoder).build();
	appenders.push(Appender::builder().build("con".to_string(), Box::new(con_recorder)));

	let root = Root::builder().build(LogLevelFilter::Off);
	let tina_root_logger =
		Logger::builder().appender("con".to_string()).additive(false)
		.build(TINA_ROOT_MOD_PATH.to_string(), conf.main_log_level);
	loggers.push(tina_root_logger);

	let log4rs_conf =
		try!(Config::builder().appenders(appenders).loggers(loggers).build(root).map_err(|_| ()));

	let handle = init_config(log4rs_conf);

	handle.map_err(|_| ()).map(|_| ())
}
<commit_msg>Logging: Add memo<commit_after>use log4rs::append::console::ConsoleAppender;
use log4rs::append::file::FileAppender;
use log4rs::config::{Appender, Logger, Config, Root};
use log4rs::encode::pattern::PatternEncoder;
use log4rs::init_config;
use log::LogLevelFilter;

const WNI_MOD_PATH: &'static str = "tina::source::wni_client";
const EEW_MOD_PATH: &'static str = "tina::destination::logging_wrapper";
const TINA_ROOT_MOD_PATH: &'static str = "tina";
const FORMAT: &'static str = "[{d(%Y/%m/%d-%H:%M:%S)(utc)}][{l}\\({f}\\)] {m}{n}";

pub struct LogConfig {
	pub wni_log_path: Option<String>,
	pub wni_log_console: bool,
	pub eew_log_path: Option<String>,
	pub eew_log_console: bool,
	pub main_log_level: LogLevelFilter
}

fn register_inspection_point(file_path: Option<String>, to_root: bool, mod_path: String,
	level: LogLevelFilter, appenders: &mut Vec<Appender>, loggers: &mut Vec<Logger>)
	-> Result<(), ()>
{
	if let Some(path) = file_path {

		let name = mod_path.clone();
		let encoder = Box::new(PatternEncoder::new(FORMAT));
		let recorder = try!(FileAppender::builder().encoder(encoder).build(path).map_err(|_| ()));
		let appender = Appender::builder().build(name.clone(), Box::new(recorder));
		let logger = Logger::builder().appender(name).additive(to_root).build(mod_path, level);
		appenders.push(appender);
		loggers.push(logger);

	} else if !to_root {

		let logger = Logger::builder().additive(false).build(mod_path, LogLevelFilter::Off);
		loggers.push(logger);
	}

	Ok(())
}

pub fn setup_logging(conf: LogConfig) -> Result<(), ()>
{
	let mut appenders = Vec::new();
	let mut loggers = Vec::new();

	// FIXME: If the main log level is above Debug, the log output of tina::source::wni_client
	//         will not be shown to the console even if conf.wni_log_console is true.
	try!(register_inspection_point(conf.wni_log_path, conf.wni_log_console,
		WNI_MOD_PATH.to_string(), LogLevelFilter::Debug, &mut appenders, &mut loggers));
	try!(register_inspection_point(conf.eew_log_path, conf.eew_log_console,
		EEW_MOD_PATH.to_string(), LogLevelFilter::Info, &mut appenders, &mut loggers));

	let con_encoder = Box::new(PatternEncoder::new(FORMAT));
	let con_recorder = ConsoleAppender::builder().encoder(con_encoder).build();
	appenders.push(Appender::builder().build("con".to_string(), Box::new(con_recorder)));

	let root = Root::builder().build(LogLevelFilter::Off);
	let tina_root_logger =
		Logger::builder().appender("con".to_string()).additive(false)
		.build(TINA_ROOT_MOD_PATH.to_string(), conf.main_log_level);
	loggers.push(tina_root_logger);

	let log4rs_conf =
		try!(Config::builder().appenders(appenders).loggers(loggers).build(root).map_err(|_| ()));

	let handle = init_config(log4rs_conf);

	handle.map_err(|_| ()).map(|_| ())
}
<|endoftext|>


<commit_before>use rustc::lint::*;
use rustc_front::hir::*;
use rustc::middle::ty;
use syntax::ast::Lit_::LitBool;
use syntax::codemap::Span;

use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block};

declare_lint!(pub SINGLE_MATCH, Warn,
              "a match statement with a single nontrivial arm (i.e, where the other arm \
               is `_ => {}`) is used; recommends `if let` instead");
declare_lint!(pub MATCH_REF_PATS, Warn,
              "a match has all arms prefixed with `&`; the match expression can be \
               dereferenced instead");
declare_lint!(pub MATCH_BOOL, Warn,
              "a match on boolean expression; recommends `if..else` block instead");

#[allow(missing_copy_implementations)]
pub struct MatchPass;

impl LintPass for MatchPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL)
    }
}

impl LateLintPass for MatchPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) { return; }
        if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node {
            // check preconditions for SINGLE_MATCH
                // only two arms
            if arms.len() == 2 &&
                // both of the arms have a single pattern and no guard
                arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                // and the second pattern is a `_` wildcard: this is not strictly necessary,
                // since the exhaustiveness check will ensure the last one is a catch-all,
                // but in some cases, an explicit match is preferred to catch situations
                // when an enum is extended, so we don't consider these cases
                arms[1].pats[0].node == PatWild &&
                // we don't want any content in the second arm (unit or empty block)
                is_unit_expr(&arms[1].body) &&
                // finally, MATCH_BOOL doesn't apply here
                (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow)
            {
                span_help_and_lint(cx, SINGLE_MATCH, expr.span,
                                   "you seem to be trying to use match for destructuring a \
                                    single pattern. Consider using `if let`",
                                   &format!("try\nif let {} = {} {}",
                                            snippet(cx, arms[0].pats[0].span, ".."),
                                            snippet(cx, ex.span, ".."),
                                            expr_block(cx, &arms[0].body, None, "..")));
            }

            // check preconditions for MATCH_BOOL
            // type of expression == bool
            if cx.tcx.expr_ty(ex).sty == ty::TyBool {
                if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards
                    let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node {
                        if let ExprLit(ref lit) = arm_bool.node {
                            if let LitBool(val) = lit.node {
                                if val {
                                    Some((&*arms[0].body, &*arms[1].body))
                                } else {
                                    Some((&*arms[1].body, &*arms[0].body))
                                }
                            } else { None }
                        } else { None }
                    } else { None };
                    if let Some((ref true_expr, ref false_expr)) = exprs {
                        if !is_unit_expr(true_expr) {
                            if !is_unit_expr(false_expr) {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {} else {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, ".."),
                                        expr_block(cx, false_expr, None, "..")));
                            } else {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, "..")));
                            }
                        } else if !is_unit_expr(false_expr) {
                            span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                "you seem to be trying to match on a boolean expression. \
                               Consider using an if..else block:",
                               &format!("try\nif !{} {}",
                                    snippet(cx, ex.span, "b"),
                                    expr_block(cx, false_expr, None, "..")));
                        } else {
                            span_lint(cx, MATCH_BOOL, expr.span,
                                   "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block");
                        }
                    } else {
                        span_lint(cx, MATCH_BOOL, expr.span,
                            "you seem to be trying to match on a boolean expression. \
                            Consider using an if..else block");
                    }
                } else {
                    span_lint(cx, MATCH_BOOL, expr.span,
                        "you seem to be trying to match on a boolean expression. \
                        Consider using an if..else block");
                }
            }
        }
        if let ExprMatch(ref ex, ref arms, source) = expr.node {
            // check preconditions for MATCH_REF_PATS
            if has_only_ref_pats(arms) {
                if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node {
                    let template = match_template(cx, expr.span, source, "", inner);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "you don't need to add `&` to both the expression \
                         and the patterns: use `{}`", template));
                } else {
                    let template = match_template(cx, expr.span, source, "*", ex);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "instead of prefixing all patterns with `&`, you can dereference the \
                         expression: `{}`", template));
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprTup(ref v) if v.is_empty() => true,
        ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true,
        _ => false,
    }
}

fn has_only_ref_pats(arms: &[Arm]) -> bool {
    let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node {
        PatRegion(..) => Some(true),  // &-patterns
        PatWild(..) => Some(false),   // an "anything" wildcard is also fine
        _ => None,                    // any other pattern is not fine
    }).collect::<Option<Vec<bool>>>();
    // look for Some(v) where there's at least one true element
    mapped.map_or(false, |v| v.iter().any(|el| *el))
}

fn match_template(cx: &LateContext,
                  span: Span,
                  source: MatchSource,
                  op: &str,
                  expr: &Expr) -> String {
    let expr_snippet = snippet(cx, expr.span, "..");
    match source {
        MatchSource::Normal => {
            format!("match {}{} {{ ...", op, expr_snippet)
        }
        MatchSource::IfLetDesugar { .. } => {
            format!("if let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::WhileLetDesugar => {
            format!("while let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::ForLoopDesugar => {
            cx.sess().span_bug(span, "for loop desugared to match with &-patterns!")
        }
    }
}
<commit_msg>Rust upgrade to rustc 1.6.0-nightly (52d95e644 2015-11-30)<commit_after>use rustc::lint::*;
use rustc_front::hir::*;
use rustc::middle::ty;
use syntax::ast::Lit_::LitBool;
use syntax::codemap::Span;

use utils::{snippet, span_lint, span_help_and_lint, in_external_macro, expr_block};

declare_lint!(pub SINGLE_MATCH, Warn,
              "a match statement with a single nontrivial arm (i.e, where the other arm \
               is `_ => {}`) is used; recommends `if let` instead");
declare_lint!(pub MATCH_REF_PATS, Warn,
              "a match has all arms prefixed with `&`; the match expression can be \
               dereferenced instead");
declare_lint!(pub MATCH_BOOL, Warn,
              "a match on boolean expression; recommends `if..else` block instead");

#[allow(missing_copy_implementations)]
pub struct MatchPass;

impl LintPass for MatchPass {
    fn get_lints(&self) -> LintArray {
        lint_array!(SINGLE_MATCH, MATCH_REF_PATS, MATCH_BOOL)
    }
}

impl LateLintPass for MatchPass {
    fn check_expr(&mut self, cx: &LateContext, expr: &Expr) {
        if in_external_macro(cx, expr.span) { return; }
        if let ExprMatch(ref ex, ref arms, MatchSource::Normal) = expr.node {
            // check preconditions for SINGLE_MATCH
                // only two arms
            if arms.len() == 2 &&
                // both of the arms have a single pattern and no guard
                arms[0].pats.len() == 1 && arms[0].guard.is_none() &&
                arms[1].pats.len() == 1 && arms[1].guard.is_none() &&
                // and the second pattern is a `_` wildcard: this is not strictly necessary,
                // since the exhaustiveness check will ensure the last one is a catch-all,
                // but in some cases, an explicit match is preferred to catch situations
                // when an enum is extended, so we don't consider these cases
                arms[1].pats[0].node == PatWild &&
                // we don't want any content in the second arm (unit or empty block)
                is_unit_expr(&arms[1].body) &&
                // finally, MATCH_BOOL doesn't apply here
                (cx.tcx.expr_ty(ex).sty != ty::TyBool || cx.current_level(MATCH_BOOL) == Allow)
            {
                span_help_and_lint(cx, SINGLE_MATCH, expr.span,
                                   "you seem to be trying to use match for destructuring a \
                                    single pattern. Consider using `if let`",
                                   &format!("try\nif let {} = {} {}",
                                            snippet(cx, arms[0].pats[0].span, ".."),
                                            snippet(cx, ex.span, ".."),
                                            expr_block(cx, &arms[0].body, None, "..")));
            }

            // check preconditions for MATCH_BOOL
            // type of expression == bool
            if cx.tcx.expr_ty(ex).sty == ty::TyBool {
                if arms.len() == 2 && arms[0].pats.len() == 1 { // no guards
                    let exprs = if let PatLit(ref arm_bool) = arms[0].pats[0].node {
                        if let ExprLit(ref lit) = arm_bool.node {
                            if let LitBool(val) = lit.node {
                                if val {
                                    Some((&*arms[0].body, &*arms[1].body))
                                } else {
                                    Some((&*arms[1].body, &*arms[0].body))
                                }
                            } else { None }
                        } else { None }
                    } else { None };
                    if let Some((ref true_expr, ref false_expr)) = exprs {
                        if !is_unit_expr(true_expr) {
                            if !is_unit_expr(false_expr) {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {} else {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, ".."),
                                        expr_block(cx, false_expr, None, "..")));
                            } else {
                                span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                    "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block:",
                                   &format!("try\nif {} {}",
                                        snippet(cx, ex.span, "b"),
                                        expr_block(cx, true_expr, None, "..")));
                            }
                        } else if !is_unit_expr(false_expr) {
                            span_help_and_lint(cx, MATCH_BOOL, expr.span,
                                "you seem to be trying to match on a boolean expression. \
                               Consider using an if..else block:",
                               &format!("try\nif !{} {}",
                                    snippet(cx, ex.span, "b"),
                                    expr_block(cx, false_expr, None, "..")));
                        } else {
                            span_lint(cx, MATCH_BOOL, expr.span,
                                   "you seem to be trying to match on a boolean expression. \
                                   Consider using an if..else block");
                        }
                    } else {
                        span_lint(cx, MATCH_BOOL, expr.span,
                            "you seem to be trying to match on a boolean expression. \
                            Consider using an if..else block");
                    }
                } else {
                    span_lint(cx, MATCH_BOOL, expr.span,
                        "you seem to be trying to match on a boolean expression. \
                        Consider using an if..else block");
                }
            }
        }
        if let ExprMatch(ref ex, ref arms, source) = expr.node {
            // check preconditions for MATCH_REF_PATS
            if has_only_ref_pats(arms) {
                if let ExprAddrOf(Mutability::MutImmutable, ref inner) = ex.node {
                    let template = match_template(cx, expr.span, source, "", inner);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "you don't need to add `&` to both the expression \
                         and the patterns: use `{}`", template));
                } else {
                    let template = match_template(cx, expr.span, source, "*", ex);
                    span_lint(cx, MATCH_REF_PATS, expr.span, &format!(
                        "instead of prefixing all patterns with `&`, you can dereference the \
                         expression: `{}`", template));
                }
            }
        }
    }
}

fn is_unit_expr(expr: &Expr) -> bool {
    match expr.node {
        ExprTup(ref v) if v.is_empty() => true,
        ExprBlock(ref b) if b.stmts.is_empty() && b.expr.is_none() => true,
        _ => false,
    }
}

fn has_only_ref_pats(arms: &[Arm]) -> bool {
    let mapped = arms.iter().flat_map(|a| &a.pats).map(|p| match p.node {
        PatRegion(..) => Some(true),  // &-patterns
        PatWild => Some(false),   // an "anything" wildcard is also fine
        _ => None,                    // any other pattern is not fine
    }).collect::<Option<Vec<bool>>>();
    // look for Some(v) where there's at least one true element
    mapped.map_or(false, |v| v.iter().any(|el| *el))
}

fn match_template(cx: &LateContext,
                  span: Span,
                  source: MatchSource,
                  op: &str,
                  expr: &Expr) -> String {
    let expr_snippet = snippet(cx, expr.span, "..");
    match source {
        MatchSource::Normal => {
            format!("match {}{} {{ ...", op, expr_snippet)
        }
        MatchSource::IfLetDesugar { .. } => {
            format!("if let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::WhileLetDesugar => {
            format!("while let ... = {}{} {{", op, expr_snippet)
        }
        MatchSource::ForLoopDesugar => {
            cx.sess().span_bug(span, "for loop desugared to match with &-patterns!")
        }
    }
}
<|endoftext|>