<commit_before>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.kind() == ::std::io::ErrorKind::TimedOut => Ok(()),
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<commit_msg>WAIT_TIMEOUT<commit_after>// Copyright (c) 2013-2016 Sandstorm Development Group, Inc. and contributors
// Licensed under the MIT License:
//
// 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.

use gj::{Promise, PromiseFulfiller};
use std::cell::{RefCell};
use std::rc::Rc;
use handle_table::{HandleTable, Handle};

struct Observer {
    read_overlapped: *mut ::miow::Overlapped,
    write_overlapped: *mut ::miow::Overlapped,
    read_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
    write_fulfiller: Option<PromiseFulfiller<u32, ::std::io::Error>>,
}

impl Observer {
    pub fn when_read_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.read_fulfiller = Some(fulfiller);
        promise
    }

    pub fn when_write_done(&mut self) -> Promise<u32, ::std::io::Error> {
        let (promise, fulfiller) = Promise::and_fulfiller();
        self.write_fulfiller = Some(fulfiller);
        promise
    }
}

pub struct Reactor {
    cp: ::miow::iocp::CompletionPort,
    observers: HandleTable<Observer>,
    statuses: Vec<::miow::iocp::CompletionStatus>,
}

impl Reactor {
    pub fn new() -> Result<Reactor, ::std::io::Error> {
        Ok(Reactor {
            cp: try!(::miow::iocp::CompletionPort::new(1)),
            observers: HandleTable::new(),
            statuses: vec![::miow::iocp::CompletionStatus::zero(); 1024]
        })
    }

    pub fn run_once(&mut self, maybe_timeout: Option<::time::Duration>)
                    -> Result<(), ::std::io::Error>
    {
        let timeout = maybe_timeout.map(|t| t.num_milliseconds() as u32); // XXX check for overflow

        match self.cp.get_many(&mut self.statuses[..], timeout) {
            Err(ref e) if e.raw_os_error() == Some(258) => Ok(()), // winapi::WAIT_TIMEOUT
            Err(e) => Err(e),
            Ok(statuses) => {
                for status in statuses {
                    let token = status.token();
                    let overlapped = status.overlapped();
                    let bytes_transferred = status.bytes_transferred();
                    let handle = Handle { val: token };
                    if self.observers[handle].read_overlapped == overlapped {
                        match self.observers[handle].read_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                    if self.observers[handle].write_overlapped == overlapped {
                        match self.observers[handle].write_fulfiller.take() {
                            None => (),
                            Some(f) => f.fulfill(bytes_transferred),
                        }
                    }
                }
                Ok(())
            }
        }

    }

    fn add_socket<T>(&mut self, sock: &T,
                     read_overlapped: *mut ::miow::Overlapped,
                     write_overlapped: *mut ::miow::Overlapped)
                     -> Result<Handle, ::std::io::Error>
        where T : ::std::os::windows::io::AsRawSocket
    {
        let observer = Observer {
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            read_fulfiller: None,
            write_fulfiller: None,
        };
        let handle = self.observers.push(observer);
        try!(self.cp.add_socket(handle.val, sock));
        Ok(handle)
    }
}

#[derive(Clone)]
pub struct SocketAddressInner {
    reactor: Rc<RefCell<Reactor>>,
    addr: ::std::net::SocketAddr,
}

impl SocketAddressInner {
    pub fn new_tcp(reactor: Rc<RefCell<Reactor>>, addr: ::std::net::SocketAddr)
                   -> SocketAddressInner
    {
        SocketAddressInner {
            reactor: reactor,
            addr: addr,
        }
    }

    pub fn connect(&self) -> Promise<SocketStreamInner, ::std::io::Error> {
        use miow::net::TcpBuilderExt;
        let builder = match self.addr {
            ::std::net::SocketAddr::V4(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v4());
                pry!(builder.bind("0.0.0.0:0"));
                builder
            }
            ::std::net::SocketAddr::V6(_) => {
                let builder = pry!(::net2::TcpBuilder::new_v6());
                pry!(builder.bind("[::]:0")); // TODO: does this work?
                builder
            }
        };

        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = pry!(
            self.reactor.borrow_mut().add_socket(&builder, &mut *read_overlapped,
                                                 &mut *write_overlapped));

        let (stream, _ready) = unsafe {
            pry!(builder.connect_overlapped(&self.addr, &mut *write_overlapped))
        };

        let reactor2 = self.reactor.clone();
        let result = self.reactor.borrow_mut().observers[handle].when_write_done().map(move |_| {
            Ok(SocketStreamInner::new_already_registered(
                reactor2, stream,
                read_overlapped, write_overlapped,
                handle))
        });

        result
    }

    pub fn listen(&mut self) -> Result<SocketListenerInner, ::std::io::Error> {
        let listener = try!(::std::net::TcpListener::bind(self.addr));
        SocketListenerInner::new(self.reactor.clone(), listener, self.addr)
    }
}

pub struct SocketListenerInner {
    reactor: Rc<RefCell<Reactor>>,
    listener: ::std::net::TcpListener,
    addr: ::std::net::SocketAddr,
    read_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub queue: Option<Promise<(),()>>,
}

impl SocketListenerInner {
    fn new(reactor: Rc<RefCell<Reactor>>, listener: ::std::net::TcpListener,
           addr: ::std::net::SocketAddr)
           -> Result<SocketListenerInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&listener, &mut *read_overlapped,
                                            ::std::ptr::null_mut()));

        Ok(SocketListenerInner {
            reactor: reactor,
            listener: listener,
            addr: addr,
            read_overlapped: read_overlapped,
            handle: handle,
            queue: None,
        })
    }

    pub fn accept_internal(inner: Rc<RefCell<SocketListenerInner>>)
                           -> Promise<SocketStreamInner, ::std::io::Error>
    {
        use miow::net::TcpListenerExt;
        let builder = match inner.borrow().addr {
            ::std::net::SocketAddr::V4(_) => pry!(::net2::TcpBuilder::new_v4()),
            ::std::net::SocketAddr::V6(_) => pry!(::net2::TcpBuilder::new_v6()),
        };

        let mut accept_addrs = ::miow::net::AcceptAddrsBuf::new();

        let &mut SocketListenerInner {
            ref reactor, ref mut listener, ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let (stream, _ready) = unsafe {
            pry!(listener.accept_overlapped(&builder,
                                            &mut accept_addrs,
                                            read_overlapped))
        };

        let reactor2 = reactor.clone();
        let result = reactor.borrow_mut().observers[handle].when_read_done().map(move |_| {
            println!("accepted!");
            SocketStreamInner::new(reactor2, stream)
        });

        result
    }
}

pub struct SocketStreamInner {
    reactor: Rc<RefCell<Reactor>>,
    stream: ::std::net::TcpStream,
    read_overlapped: Box<::miow::Overlapped>,
    write_overlapped: Box<::miow::Overlapped>,
    handle: Handle,
    pub read_queue: Option<Promise<(),()>>,
    pub write_queue: Option<Promise<(),()>>,
}

impl SocketStreamInner {
    fn new(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream)
           -> Result<SocketStreamInner, ::std::io::Error>
    {
        let mut read_overlapped = Box::new(::miow::Overlapped::zero());
        let mut write_overlapped = Box::new(::miow::Overlapped::zero());
        let handle = try!(
            reactor.borrow_mut().add_socket(&stream, &mut *read_overlapped,
                                            &mut *write_overlapped));
        Ok(SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        })
    }

    fn new_already_registered(reactor: Rc<RefCell<Reactor>>, stream: ::std::net::TcpStream,
                              read_overlapped: Box<::miow::Overlapped>,
                              write_overlapped: Box<::miow::Overlapped>,
                              handle: Handle)
           -> SocketStreamInner
    {
        SocketStreamInner {
            reactor: reactor,
            stream: stream,
            read_overlapped: read_overlapped,
            write_overlapped: write_overlapped,
            handle: handle,
            read_queue: None,
            write_queue: None,
        }
    }

    pub fn try_read_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                                mut buf: T,
                                already_read: usize,
                                min_bytes: usize)
                                -> Promise<(T, usize), ::std::io::Error>
        where T: AsMut<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_read >= min_bytes {
            return Promise::ok((buf, already_read));
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor, ref mut stream,
            ref mut read_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.read_overlapped(&mut buf.as_mut()[already_read..], read_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_read_done().then(move |n| {
            println!("read transferred this many bytes: {}", n);
            let total_read = n as usize + already_read;
            if n == 0 {
                println!("EOF");
                Promise::ok((buf, total_read))
            } else {
                SocketStreamInner::try_read_internal(inner2, buf, total_read, min_bytes)
            }
        });

        result
    }

    pub fn write_internal<T>(inner: Rc<RefCell<SocketStreamInner>>,
                             buf: T,
                             already_written: usize) -> Promise<T, ::std::io::Error>
        where T: AsRef<[u8]>
    {
        use ::miow::net::TcpStreamExt;

        if already_written == buf.as_ref().len() {
            return Promise::ok(buf)
        }

        let inner2 = inner.clone();
        let &mut SocketStreamInner {
            ref reactor,
            ref stream,
            ref mut write_overlapped, handle,
            ..
        } =  &mut *inner.borrow_mut();

        let _done = unsafe {
            pry!(stream.write_overlapped(&buf.as_ref()[already_written ..], write_overlapped))
        };

        let result = reactor.borrow_mut().observers[handle].when_write_done().then(move |n| {
            println!("write transferred this many bytes: {}", n);
            let total_written = n as usize + already_written;
            if n == 0 {
                println!("wrote zero bytes!?");
            }

            SocketStreamInner::write_internal(inner2, buf, total_written)
        });

        result
    }
}
<|endoftext|>


<commit_before>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LinkErrorKind {
}

fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str {
    match e {
        _ => unimplemented!(),
    }
}

impl Display for LinkErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", link_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct LinkError {
    kind: LinkErrorKind,
    cause: Option<Box<Error>>,
}

impl LinkError {

    pub fn new(errtype: LinkErrorKind, cause: Option<Box<Error>>) -> LinkError {
        LinkError {
            kind: errtype,
            cause: cause,
        }
    }

}

impl Display for LinkError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", link_error_type_as_str(&self.kind)));
        Ok(())
    }

}

impl Error for LinkError {

    fn description(&self) -> &str {
        link_error_type_as_str(&self.kind)
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}
<commit_msg>Add Error kinds<commit_after>use std::error::Error;
use std::fmt::Error as FmtError;
use std::clone::Clone;
use std::fmt::{Debug, Display, Formatter};
use std::fmt;

#[derive(Clone, Copy, Debug, PartialEq)]
pub enum LinkErrorKind {
    EntryHeaderReadError,
    EntryHeaderWriteError,
    ExistingLinkTypeWrong,
}

fn link_error_type_as_str(e: &LinkErrorKind) -> &'static str {
    match e {
        &LinkErrorKind::EntryHeaderReadError
            => "Error while reading an entry header",

        &LinkErrorKind::EntryHeaderWriteError
            => "Error while writing an entry header",

        &LinkErrorKind::ExistingLinkTypeWrong
            => "Existing link entry has wrong type",
    }
}

impl Display for LinkErrorKind {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "{}", link_error_type_as_str(self)));
        Ok(())
    }

}

#[derive(Debug)]
pub struct LinkError {
    kind: LinkErrorKind,
    cause: Option<Box<Error>>,
}

impl LinkError {

    pub fn new(errtype: LinkErrorKind, cause: Option<Box<Error>>) -> LinkError {
        LinkError {
            kind: errtype,
            cause: cause,
        }
    }

}

impl Display for LinkError {

    fn fmt(&self, fmt: &mut Formatter) -> Result<(), FmtError> {
        try!(write!(fmt, "[{}]", link_error_type_as_str(&self.kind)));
        Ok(())
    }

}

impl Error for LinkError {

    fn description(&self) -> &str {
        link_error_type_as_str(&self.kind)
    }

    fn cause(&self) -> Option<&Error> {
        self.cause.as_ref().map(|e| &**e)
    }

}
<|endoftext|>


<commit_before>use std::convert::Into;
use std::collections::BTreeMap;
use std::ops::{DerefMut, Deref};

use toml::Value;

use libimagstore::storeid::IntoStoreId;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagtag::tag::Tag;
use libimagtag::tagable::Tagable;
use libimagtag::result::Result as TagResult;
use libimagtag::error::{TagError, TagErrorKind};

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let mut lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.err().unwrap()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();
                let mut header = entry.get_header_mut();
                let setres = header.set("note", Value::Table(BTreeMap::new()));
                if setres.is_err() {
                    return Err(NE::new(NEK::StoreWriteError, Some(Box::new(setres.err().unwrap()))));
                }

                let setres = header.set("note.name", Value::String(name));
                if setres.is_err() {
                    return Err(NE::new(NEK::StoreWriteError, Some(Box::new(setres.err().unwrap()))));
                }
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.deref_mut().get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let mut header = self.entry.deref().get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.deref_mut().get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.deref().get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.deref().get_tags()
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> TagResult<()> {
        self.entry.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: &Tag) -> TagResult<bool> {
        self.entry.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &Vec<Tag>) -> TagResult<bool> {
        self.entry.deref().has_tags(ts)
    }

}

<commit_msg>lib: Add Note::all_notes()<commit_after>use std::convert::Into;
use std::collections::BTreeMap;
use std::ops::{DerefMut, Deref};

use toml::Value;

use libimagstore::storeid::IntoStoreId;
use libimagstore::storeid::StoreId;
use libimagstore::storeid::StoreIdIterator;
use libimagstore::store::FileLockEntry;
use libimagstore::store::Store;
use libimagtag::tag::Tag;
use libimagtag::tagable::Tagable;
use libimagtag::result::Result as TagResult;
use libimagtag::error::{TagError, TagErrorKind};

use module_path::ModuleEntryPath;
use result::Result;
use error::NoteError as NE;
use error::NoteErrorKind as NEK;

pub struct Note<'a> {
    entry: FileLockEntry<'a>,
}

impl<'a> Note<'a> {

    pub fn new(store: &Store, name: String, text: String) -> Result<Note> {
        use std::ops::DerefMut;

        debug!("Creating new Note: '{}'", name);
        let fle = {
            let mut lockentry = store.create(ModuleEntryPath::new(name.clone()).into_storeid());
            if lockentry.is_err() {
                return Err(NE::new(NEK::StoreWriteError, Some(Box::new(lockentry.err().unwrap()))));
            }
            let mut lockentry = lockentry.unwrap();

            {
                let mut entry  = lockentry.deref_mut();
                let mut header = entry.get_header_mut();
                let setres = header.set("note", Value::Table(BTreeMap::new()));
                if setres.is_err() {
                    return Err(NE::new(NEK::StoreWriteError, Some(Box::new(setres.err().unwrap()))));
                }

                let setres = header.set("note.name", Value::String(name));
                if setres.is_err() {
                    return Err(NE::new(NEK::StoreWriteError, Some(Box::new(setres.err().unwrap()))));
                }
            }

            lockentry
        };

        Ok(Note { entry: fle })
    }

    pub fn set_name(&mut self, n: String) -> Result<()> {
        let mut header = self.entry.deref_mut().get_header_mut();
        header.set("note.name", Value::String(n))
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|_| ())
    }

    pub fn get_name(&self) -> Result<String> {
        let mut header = self.entry.deref().get_header();
        match header.read("note.name") {
            Ok(Some(Value::String(s))) => Ok(String::from(s)),
            Ok(_)                => {
                let e = NE::new(NEK::HeaderTypeError, None);
                Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
            },
            Err(e) => Err(NE::new(NEK::StoreReadError, Some(Box::new(e))))
        }
    }

    pub fn set_text(&mut self, n: String) {
        *self.entry.deref_mut().get_content_mut() = n
    }

    pub fn get_text(&self) -> &String {
        self.entry.deref().get_content()
    }

    pub fn delete(store: &Store, name: String) -> Result<()> {
        store.delete(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
    }

    pub fn retrieve(store: &Store, name: String) -> Result<Note> {
        store.retrieve(ModuleEntryPath::new(name).into_storeid())
            .map_err(|e| NE::new(NEK::StoreWriteError, Some(Box::new(e))))
            .map(|entry| Note { entry: entry })
    }

    pub fn all_notes(store: &Store) -> Result<NoteIterator> {
        store.retrieve_for_module("notes")
            .map(|iter| NoteIterator::new(store, iter))
            .map_err(|e| NE::new(NEK::StoreReadError, Some(Box::new(e))))
    }

}

impl<'a> Tagable for Note<'a> {

    fn get_tags(&self) -> TagResult<Vec<Tag>> {
        self.entry.deref().get_tags()
    }

    fn set_tags(&mut self, ts: Vec<Tag>) -> TagResult<()> {
        self.entry.deref_mut().set_tags(ts)
    }

    fn add_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().add_tag(t)
    }

    fn remove_tag(&mut self, t: Tag) -> TagResult<()> {
        self.entry.deref_mut().remove_tag(t)
    }

    fn has_tag(&self, t: &Tag) -> TagResult<bool> {
        self.entry.deref().has_tag(t)
    }

    fn has_tags(&self, ts: &Vec<Tag>) -> TagResult<bool> {
        self.entry.deref().has_tags(ts)
    }

}

trait FromStoreId {
    fn from_storeid<'a>(&'a Store, StoreId) -> Result<Note<'a>>;
}

impl<'a> FromStoreId for Note<'a> {

    fn from_storeid<'b>(store: &'b Store, id: StoreId) -> Result<Note<'b>> {
        debug!("Loading note from storeid: '{:?}'", id);
        match store.retrieve(id) {
            Err(e)    => Err(NE::new(NEK::StoreReadError, Some(Box::new(e)))),
            Ok(entry) => Ok(Note { entry: entry }),
        }
    }

}

pub struct NoteIterator<'a> {
    store: &'a Store,
    iditer: StoreIdIterator,
}

impl<'a> NoteIterator<'a> {

    pub fn new(store: &'a Store, iditer: StoreIdIterator) -> NoteIterator<'a> {
        NoteIterator {
            store: store,
            iditer: iditer,
        }
    }

}

impl<'a> Iterator for NoteIterator<'a> {
    type Item = Result<Note<'a>>;

    fn next(&mut self) -> Option<Result<Note<'a>>> {
        self.iditer
            .next()
            .map(|id| Note::from_storeid(self.store, id))
    }

}

<|endoftext|>


<commit_before>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::Store;

/// The Runtime object
///
/// This object contains the complete runtime environment of the imag application running.
#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /// Gets the CLI spec for the program and retreives the config file path (or uses the default on
    /// in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
    /// and builds the Runtime object with it.
    ///
    /// The cli_spec object should be initially build with the ::get_default_cli_builder() function.
    pub fn new(mut cli_spec: App<'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        use std::env;
        use std::io::stdout;

        use clap::Shell;

        use libimagerror::trace::trace_error;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_spec.clone().get_matches();

        let is_debugging = matches.is_present("debugging");
        let is_verbose   = matches.is_present("verbosity");
        let colored      = !matches.is_present("no-color-output");

        Runtime::init_logger(is_debugging, is_verbose, colored);

        match matches.value_of(Runtime::arg_generate_compl()) {
            Some(shell) => {
                debug!("Generating shell completion script, writing to stdout");
                let shell   = shell.parse::<Shell>().unwrap(); // clap has our back here.
                let appname = String::from(cli_spec.get_name());
                cli_spec.gen_completions_to(appname, shell, &mut stdout());
            },
            _ => debug!("Not generating shell completion script"),
        }

        let rtp : PathBuf = matches.value_of("runtimepath")
            .map_or_else(|| {
                env::var("HOME")
                    .map(PathBuf::from)
                    .map(|mut p| { p.push(".imag"); p})
                    .unwrap_or_else(|_| {
                        panic!("You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways.");
                    })
            }, PathBuf::from);
        let storepath = matches.value_of("storepath")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let configpath = matches.value_of("config")
                                .map_or_else(|| rtp.clone(), PathBuf::from);

        debug!("RTP path    = {:?}", rtp);
        debug!("Store path  = {:?}", storepath);
        debug!("Config path = {:?}", configpath);

        let cfg = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(mut cfg) => {
                if let Err(e) = cfg.override_config(get_override_specs(&matches)) {
                    error!("Could not apply config overrides");
                    trace_error(&e);

                    // TODO: continue question (interactive)
                }

                Some(cfg)
            }
        };

        let store_config = match cfg {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", cfg).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        Store::new(storepath.clone(), store_config).map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: cfg,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    ///
    /// Get a commandline-interface builder object from `clap`
    ///
    /// This commandline interface builder object already contains some predefined interface flags:
    ///   * -v | --verbose for verbosity
    ///   * --debug for debugging
    ///   * -c <file> | --config <file> for alternative configuration file
    ///   * -r <path> | --rtp <path> for alternative runtimepath
    ///   * --store <path> for alternative store path
    /// Each has the appropriate help text included.
    ///
    /// The `appname` shall be "imag-<command>".
    ///
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name(Runtime::arg_verbosity_name())
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_debugging_name())
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_no_color_output_name())
                .long("no-color")
                .help("Disable color output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_config_name())
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_config_override_name())
                 .long("override-config")
                 .help("Override a configuration settings. Use 'key=value' pairs, where the key is a path in the TOML configuration. The value must be present in the configuration and be convertible to the type of the configuration setting. If the argument does not contain a '=', it gets ignored. Setting Arrays and Tables is not yet supported.")
                 .required(false)
                 .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_runtimepath_name())
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_storepath_name())
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_editor_name())
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_generate_compl())
                .long("generate-commandline-completion")
                .help("Generate the commandline completion for bash or zsh or fish")
                .required(false)
                .takes_value(true)
                .value_name("SHELL")
                .possible_values(&["bash", "fish", "zsh"]))

    }

    /// Get the argument names of the Runtime which are available
    pub fn arg_names() -> Vec<&'static str> {
        vec![
            Runtime::arg_verbosity_name(),
            Runtime::arg_debugging_name(),
            Runtime::arg_no_color_output_name(),
            Runtime::arg_config_name(),
            Runtime::arg_config_override_name(),
            Runtime::arg_runtimepath_name(),
            Runtime::arg_storepath_name(),
            Runtime::arg_editor_name(),
        ]
    }

    /// Get the verbosity argument name for the Runtime
    pub fn arg_verbosity_name() -> &'static str {
        "verbosity"
    }

    /// Get the debugging argument name for the Runtime
    pub fn arg_debugging_name() -> &'static str {
        "debugging"
    }

    /// Get the argument name for no color output of the Runtime
    pub fn arg_no_color_output_name() -> &'static str {
        "no-color-output"
    }

    /// Get the config argument name for the Runtime
    pub fn arg_config_name() -> &'static str {
        "config"
    }

    /// Get the config-override argument name for the Runtime
    pub fn arg_config_override_name() -> &'static str {
        "config-override"
    }

    /// Get the runtime argument name for the Runtime
    pub fn arg_runtimepath_name() -> &'static str {
        "runtimepath"
    }

    /// Get the storepath argument name for the Runtime
    pub fn arg_storepath_name() -> &'static str {
        "storepath"
    }

    /// Get the editor argument name for the Runtime
    pub fn arg_editor_name() -> &'static str {
        "editor"
    }

    /// Get the argument name for generating the completion
    pub fn arg_generate_compl() -> &'static str {
        "generate-completion"
    }

    /// Initialize the internal logger
    fn init_logger(is_debugging: bool, is_verbose: bool, colored: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Warn
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()).with_color(colored))
            })
            .map_err(|_| {
                panic!("Could not setup logger");
            })
            .ok();
        }
    }

    /// Get the verbosity flag value
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /// Get the debugging flag value
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /// Get the runtimepath
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /// Get the commandline interface matches
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /// Get the configuration object
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /// Get the store object
    pub fn store(&self) -> &Store {
        &self.store
    }

    /// Change the store backend to stdout
    ///
    /// For the documentation on purpose and cavecats, have a look at the documentation of the
    /// `Store::reset_backend()` function.
    ///
    pub fn store_backend_to_stdio(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::*;
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use std::rc::Rc;
        use std::cell::RefCell;

        let mut input = ::std::io::stdin();
        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdIoFileAbstraction::new(&mut input, output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    pub fn store_backend_to_stdout(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use libimagstore::file_abstraction::stdio::out::StdoutFileAbstraction;
        use std::rc::Rc;
        use std::cell::RefCell;

        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdoutFileAbstraction::new(output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    /// Get a editor command object which can be called to open the $EDITOR
    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or({
                match self.configuration {
                    Some(ref c) => c.editor().cloned(),
                    _ => None,
                }
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

fn get_override_specs(matches: &ArgMatches) -> Vec<String> {
    matches
        .values_of("config-override")
        .map(|values| {
             values
             .filter(|s| {
                 let b = s.contains("=");
                 if !b { warn!("override '{}' does not contain '=' - will be ignored!", s); }
                 b
             })
             .map(String::from)
             .collect()
        })
        .unwrap_or(vec![])
}

<commit_msg>Print error while panicing<commit_after>//
// imag - the personal information management suite for the commandline
// Copyright (C) 2015, 2016 Matthias Beyer <mail@beyermatthias.de> and contributors
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; version
// 2.1 of the License.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
//

use std::path::PathBuf;
use std::process::Command;
use std::env;
use std::io::stderr;
use std::io::Write;

pub use clap::App;

use clap::{Arg, ArgMatches};
use log;
use log::LogLevelFilter;

use configuration::Configuration;
use error::RuntimeError;
use error::RuntimeErrorKind;
use error::MapErrInto;
use logger::ImagLogger;

use libimagstore::store::Store;

/// The Runtime object
///
/// This object contains the complete runtime environment of the imag application running.
#[derive(Debug)]
pub struct Runtime<'a> {
    rtp: PathBuf,
    configuration: Option<Configuration>,
    cli_matches: ArgMatches<'a>,
    store: Store,
}

impl<'a> Runtime<'a> {

    /// Gets the CLI spec for the program and retreives the config file path (or uses the default on
    /// in $HOME/.imag/config, $XDG_CONFIG_DIR/imag/config or from env("$IMAG_CONFIG")
    /// and builds the Runtime object with it.
    ///
    /// The cli_spec object should be initially build with the ::get_default_cli_builder() function.
    pub fn new(mut cli_spec: App<'a, 'a>) -> Result<Runtime<'a>, RuntimeError> {
        use std::env;
        use std::io::stdout;

        use clap::Shell;

        use libimagerror::trace::trace_error;
        use libimagerror::into::IntoError;

        use configuration::error::ConfigErrorKind;

        let matches = cli_spec.clone().get_matches();

        let is_debugging = matches.is_present("debugging");
        let is_verbose   = matches.is_present("verbosity");
        let colored      = !matches.is_present("no-color-output");

        Runtime::init_logger(is_debugging, is_verbose, colored);

        match matches.value_of(Runtime::arg_generate_compl()) {
            Some(shell) => {
                debug!("Generating shell completion script, writing to stdout");
                let shell   = shell.parse::<Shell>().unwrap(); // clap has our back here.
                let appname = String::from(cli_spec.get_name());
                cli_spec.gen_completions_to(appname, shell, &mut stdout());
            },
            _ => debug!("Not generating shell completion script"),
        }

        let rtp : PathBuf = matches.value_of("runtimepath")
            .map_or_else(|| {
                env::var("HOME")
                    .map(PathBuf::from)
                    .map(|mut p| { p.push(".imag"); p})
                    .unwrap_or_else(|_| {
                        panic!("You seem to be $HOME-less. Please get a $HOME before using this software. We are sorry for you and hope you have some accommodation anyways.");
                    })
            }, PathBuf::from);
        let storepath = matches.value_of("storepath")
                                .map_or_else(|| {
                                    let mut spath = rtp.clone();
                                    spath.push("store");
                                    spath
                                }, PathBuf::from);

        let configpath = matches.value_of("config")
                                .map_or_else(|| rtp.clone(), PathBuf::from);

        debug!("RTP path    = {:?}", rtp);
        debug!("Store path  = {:?}", storepath);
        debug!("Config path = {:?}", configpath);

        let cfg = match Configuration::new(&configpath) {
            Err(e) => if e.err_type() != ConfigErrorKind::NoConfigFileFound {
                return Err(RuntimeErrorKind::Instantiate.into_error_with_cause(Box::new(e)));
            } else {
                warn!("No config file found.");
                warn!("Continuing without configuration file");
                None
            },

            Ok(mut cfg) => {
                if let Err(e) = cfg.override_config(get_override_specs(&matches)) {
                    error!("Could not apply config overrides");
                    trace_error(&e);

                    // TODO: continue question (interactive)
                }

                Some(cfg)
            }
        };

        let store_config = match cfg {
            Some(ref c) => c.store_config().cloned(),
            None        => None,
        };

        if is_debugging {
            write!(stderr(), "Config: {:?}\n", cfg).ok();
            write!(stderr(), "Store-config: {:?}\n", store_config).ok();
        }

        Store::new(storepath.clone(), store_config).map(|store| {
            Runtime {
                cli_matches: matches,
                configuration: cfg,
                rtp: rtp,
                store: store,
            }
        })
        .map_err_into(RuntimeErrorKind::Instantiate)
    }

    ///
    /// Get a commandline-interface builder object from `clap`
    ///
    /// This commandline interface builder object already contains some predefined interface flags:
    ///   * -v | --verbose for verbosity
    ///   * --debug for debugging
    ///   * -c <file> | --config <file> for alternative configuration file
    ///   * -r <path> | --rtp <path> for alternative runtimepath
    ///   * --store <path> for alternative store path
    /// Each has the appropriate help text included.
    ///
    /// The `appname` shall be "imag-<command>".
    ///
    pub fn get_default_cli_builder(appname: &'a str,
                                   version: &'a str,
                                   about: &'a str)
        -> App<'a, 'a>
    {
        App::new(appname)
            .version(version)
            .author("Matthias Beyer <mail@beyermatthias.de>")
            .about(about)
            .arg(Arg::with_name(Runtime::arg_verbosity_name())
                .short("v")
                .long("verbose")
                .help("Enables verbosity")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_debugging_name())
                .long("debug")
                .help("Enables debugging output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_no_color_output_name())
                .long("no-color")
                .help("Disable color output")
                .required(false)
                .takes_value(false))

            .arg(Arg::with_name(Runtime::arg_config_name())
                .long("config")
                .help("Path to alternative config file")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_config_override_name())
                 .long("override-config")
                 .help("Override a configuration settings. Use 'key=value' pairs, where the key is a path in the TOML configuration. The value must be present in the configuration and be convertible to the type of the configuration setting. If the argument does not contain a '=', it gets ignored. Setting Arrays and Tables is not yet supported.")
                 .required(false)
                 .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_runtimepath_name())
                .long("rtp")
                .help("Alternative runtimepath")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_storepath_name())
                .long("store")
                .help("Alternative storepath. Must be specified as full path, can be outside of the RTP")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_editor_name())
                .long("editor")
                .help("Set editor")
                .required(false)
                .takes_value(true))

            .arg(Arg::with_name(Runtime::arg_generate_compl())
                .long("generate-commandline-completion")
                .help("Generate the commandline completion for bash or zsh or fish")
                .required(false)
                .takes_value(true)
                .value_name("SHELL")
                .possible_values(&["bash", "fish", "zsh"]))

    }

    /// Get the argument names of the Runtime which are available
    pub fn arg_names() -> Vec<&'static str> {
        vec![
            Runtime::arg_verbosity_name(),
            Runtime::arg_debugging_name(),
            Runtime::arg_no_color_output_name(),
            Runtime::arg_config_name(),
            Runtime::arg_config_override_name(),
            Runtime::arg_runtimepath_name(),
            Runtime::arg_storepath_name(),
            Runtime::arg_editor_name(),
        ]
    }

    /// Get the verbosity argument name for the Runtime
    pub fn arg_verbosity_name() -> &'static str {
        "verbosity"
    }

    /// Get the debugging argument name for the Runtime
    pub fn arg_debugging_name() -> &'static str {
        "debugging"
    }

    /// Get the argument name for no color output of the Runtime
    pub fn arg_no_color_output_name() -> &'static str {
        "no-color-output"
    }

    /// Get the config argument name for the Runtime
    pub fn arg_config_name() -> &'static str {
        "config"
    }

    /// Get the config-override argument name for the Runtime
    pub fn arg_config_override_name() -> &'static str {
        "config-override"
    }

    /// Get the runtime argument name for the Runtime
    pub fn arg_runtimepath_name() -> &'static str {
        "runtimepath"
    }

    /// Get the storepath argument name for the Runtime
    pub fn arg_storepath_name() -> &'static str {
        "storepath"
    }

    /// Get the editor argument name for the Runtime
    pub fn arg_editor_name() -> &'static str {
        "editor"
    }

    /// Get the argument name for generating the completion
    pub fn arg_generate_compl() -> &'static str {
        "generate-completion"
    }

    /// Initialize the internal logger
    fn init_logger(is_debugging: bool, is_verbose: bool, colored: bool) {
        use std::env::var as env_var;
        use env_logger;

        if env_var("IMAG_LOG_ENV").is_ok() {
            env_logger::init().unwrap();
        } else {
            let lvl = if is_debugging {
                LogLevelFilter::Debug
            } else if is_verbose {
                LogLevelFilter::Info
            } else {
                LogLevelFilter::Warn
            };

            log::set_logger(|max_log_lvl| {
                max_log_lvl.set(lvl);
                debug!("Init logger with {}", lvl);
                Box::new(ImagLogger::new(lvl.to_log_level().unwrap()).with_color(colored))
            })
            .map_err(|e| panic!("Could not setup logger: {:?}", e))
            .ok();
        }
    }

    /// Get the verbosity flag value
    pub fn is_verbose(&self) -> bool {
        self.cli_matches.is_present("verbosity")
    }

    /// Get the debugging flag value
    pub fn is_debugging(&self) -> bool {
        self.cli_matches.is_present("debugging")
    }

    /// Get the runtimepath
    pub fn rtp(&self) -> &PathBuf {
        &self.rtp
    }

    /// Get the commandline interface matches
    pub fn cli(&self) -> &ArgMatches {
        &self.cli_matches
    }

    /// Get the configuration object
    pub fn config(&self) -> Option<&Configuration> {
        self.configuration.as_ref()
    }

    /// Get the store object
    pub fn store(&self) -> &Store {
        &self.store
    }

    /// Change the store backend to stdout
    ///
    /// For the documentation on purpose and cavecats, have a look at the documentation of the
    /// `Store::reset_backend()` function.
    ///
    pub fn store_backend_to_stdio(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::*;
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use std::rc::Rc;
        use std::cell::RefCell;

        let mut input = ::std::io::stdin();
        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdIoFileAbstraction::new(&mut input, output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    pub fn store_backend_to_stdout(&mut self) -> Result<(), RuntimeError> {
        use libimagstore::file_abstraction::stdio::mapper::json::JsonMapper;
        use libimagstore::file_abstraction::stdio::out::StdoutFileAbstraction;
        use std::rc::Rc;
        use std::cell::RefCell;

        let output    = ::std::io::stdout();
        let output    = Rc::new(RefCell::new(output));
        let mapper    = JsonMapper::new();

        StdoutFileAbstraction::new(output, mapper)
            .map_err_into(RuntimeErrorKind::Instantiate)
            .and_then(|backend| {
                self.store
                    .reset_backend(Box::new(backend))
                    .map_err_into(RuntimeErrorKind::Instantiate)
            })
    }

    /// Get a editor command object which can be called to open the $EDITOR
    pub fn editor(&self) -> Option<Command> {
        self.cli()
            .value_of("editor")
            .map(String::from)
            .or({
                match self.configuration {
                    Some(ref c) => c.editor().cloned(),
                    _ => None,
                }
            })
            .or(env::var("EDITOR").ok())
            .map(Command::new)
    }
}

fn get_override_specs(matches: &ArgMatches) -> Vec<String> {
    matches
        .values_of("config-override")
        .map(|values| {
             values
             .filter(|s| {
                 let b = s.contains("=");
                 if !b { warn!("override '{}' does not contain '=' - will be ignored!", s); }
                 b
             })
             .map(String::from)
             .collect()
        })
        .unwrap_or(vec![])
}

<|endoftext|>


<commit_before>//! Callback container for Stream.

use crate::sync::RwLock;
use maybe_owned::MaybeOwned;
use std::fmt;
use std::sync::atomic::{AtomicBool, Ordering};

#[cfg(feature = "crossbeam-utils")]
use crossbeam_utils::thread;

/// Function that becomes uncallable after it returns false.
///
/// Callbacks use a `MaybeOwned<T>` argument so we can choose at runtime if we will send a ref or an owned value.
struct FnCell<T> {
    f: Box<dyn Fn(MaybeOwned<'_, T>) -> bool + Send + Sync>,
    alive: AtomicBool,
}

impl<T> FnCell<T> {
    /// Creates a new `FnCell` from the supplied closure.
    fn new<F>(f: F) -> Self
    where
        F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static,
    {
        FnCell {
            f: Box::new(f),
            alive: AtomicBool::new(true),
        }
    }

    /// Calls the stored function and updates it's callable status.
    fn call(&self, arg: MaybeOwned<'_, T>) -> bool {
        if self.alive.load(Ordering::Relaxed) {
            let is_alive = (self.f)(arg);
            if !is_alive {
                self.alive.store(false, Ordering::Relaxed);
            }
            is_alive
        } else {
            false
        }
    }

    /// Checks if this function can still be called.
    fn is_alive(&self) -> bool {
        self.alive.load(Ordering::Relaxed)
    }
}

impl<T> fmt::Debug for FnCell<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "FnCell {{ f: Fn@{:p}, alive: {:?} }}",
            self.f, self.alive
        )
    }
}

/// A collection of callbacks.
#[derive(Debug)]
pub struct Callbacks<T> {
    fs: RwLock<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T> {
    /// Creates an empty callback list.
    pub fn new() -> Self {
        Callbacks {
            fs: Default::default(),
        }
    }

    /// Adds a new closure to the callback list.
    pub fn push<F>(&self, cb: F)
    where
        F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static,
    {
        self.fs.write().push(FnCell::new(cb))
    }

    /// Sends an owned value.
    ///
    /// This sends a ref to the first N-1 callbacks, and the owned value to the last.
    pub fn call_owned(&self, arg: T) {
        let fs = self.fs.read();
        let n = fs.len();

        let mut i = 0;
        let mut all_alive = true;
        for _ in 1..n {
            all_alive &= fs[i].call(MaybeOwned::Borrowed(&arg));
            i += 1;
        }
        if n > 0 {
            all_alive &= fs[i].call(MaybeOwned::Owned(arg));
        }
        drop(fs);

        if !all_alive {
            self.cleanup();
        }
    }

    /// Sends a value by reference.
    pub fn call_ref(&self, arg: &T) {
        let all_alive = self
            .fs
            .read()
            .iter()
            .map(|f| f.call(MaybeOwned::Borrowed(arg)))
            .fold(true, |a, alive| a & alive);

        if !all_alive {
            self.cleanup();
        }
    }

    /// Sends a value.
    #[inline]
    pub fn call<'a>(&self, arg: impl Into<MaybeOwned<'a, T>>)
    where
        T: 'a,
    {
        match arg.into() {
            MaybeOwned::Owned(v) => self.call_owned(v),
            MaybeOwned::Borrowed(r) => self.call_ref(r),
        }
    }

    /// Sends a value using multiple threads.
    #[cfg(feature = "crossbeam-utils")]
    pub fn call_parallel(&self, arg: &T)
    where
        T: Sync,
    {
        let fs = self.fs.read();
        let n = fs.len();
        // nothing to do
        if n == 0 {
            return;
        }
        // only 1 callback, just run it on this thread
        if n == 1 {
            if !fs[0].call(MaybeOwned::Borrowed(arg)) {
                self.cleanup();
            }
            return;
        }
        // 2+ callbacks, we need more threads
        let all_alive = AtomicBool::new(true);
        thread::scope(|scope| {
            let all_alive = &all_alive;

            let mut i = 0;
            // spawn N-1 threads
            for _ in 1..n {
                let f = &fs[i];
                scope.spawn(move |_| {
                    if !f.call(MaybeOwned::Borrowed(arg)) {
                        all_alive.store(false, Ordering::Relaxed);
                    }
                });
                i += 1;
            }
            // run the last callback on current thread
            let f = &fs[i];
            if !f.call(MaybeOwned::Borrowed(arg)) {
                all_alive.store(false, Ordering::Relaxed);
            }
        })
        .unwrap();
        // after all threads finished, continue with the cleanup
        drop(fs);
        if all_alive.load(Ordering::Relaxed) {
            self.cleanup();
        }
    }

    /// Removes the dead callbacks.
    fn cleanup(&self) {
        if let Some(mut fs) = self.fs.try_write() {
            fs.retain(FnCell::is_alive);
        }
    }

    #[cfg(test)]
    pub(crate) fn len(&self) -> usize {
        self.fs.read().len()
    }
}

impl<T> Default for Callbacks<T> {
    fn default() -> Self {
        Callbacks::new()
    }
}
<commit_msg>removed redundant let binding<commit_after>//! Callback container for Stream.

use crate::sync::RwLock;
use maybe_owned::MaybeOwned;
use std::fmt;
use std::sync::atomic::{AtomicBool, Ordering};

#[cfg(feature = "crossbeam-utils")]
use crossbeam_utils::thread;

/// Function that becomes uncallable after it returns false.
///
/// Callbacks use a `MaybeOwned<T>` argument so we can choose at runtime if we will send a ref or an owned value.
struct FnCell<T> {
    f: Box<dyn Fn(MaybeOwned<'_, T>) -> bool + Send + Sync>,
    alive: AtomicBool,
}

impl<T> FnCell<T> {
    /// Creates a new `FnCell` from the supplied closure.
    fn new<F>(f: F) -> Self
    where
        F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static,
    {
        FnCell {
            f: Box::new(f),
            alive: AtomicBool::new(true),
        }
    }

    /// Calls the stored function and updates it's callable status.
    fn call(&self, arg: MaybeOwned<'_, T>) -> bool {
        if self.alive.load(Ordering::Relaxed) {
            let is_alive = (self.f)(arg);
            if !is_alive {
                self.alive.store(false, Ordering::Relaxed);
            }
            is_alive
        } else {
            false
        }
    }

    /// Checks if this function can still be called.
    fn is_alive(&self) -> bool {
        self.alive.load(Ordering::Relaxed)
    }
}

impl<T> fmt::Debug for FnCell<T> {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(
            f,
            "FnCell {{ f: Fn@{:p}, alive: {:?} }}",
            self.f, self.alive
        )
    }
}

/// A collection of callbacks.
#[derive(Debug)]
pub struct Callbacks<T> {
    fs: RwLock<Vec<FnCell<T>>>,
}

impl<T> Callbacks<T> {
    /// Creates an empty callback list.
    pub fn new() -> Self {
        Callbacks {
            fs: Default::default(),
        }
    }

    /// Adds a new closure to the callback list.
    pub fn push<F>(&self, cb: F)
    where
        F: Fn(MaybeOwned<'_, T>) -> bool + Send + Sync + 'static,
    {
        self.fs.write().push(FnCell::new(cb))
    }

    /// Sends an owned value.
    ///
    /// This sends a ref to the first N-1 callbacks, and the owned value to the last.
    pub fn call_owned(&self, arg: T) {
        let fs = self.fs.read();
        let n = fs.len();

        let mut i = 0;
        let mut all_alive = true;
        for _ in 1..n {
            all_alive &= fs[i].call(MaybeOwned::Borrowed(&arg));
            i += 1;
        }
        if n > 0 {
            all_alive &= fs[i].call(MaybeOwned::Owned(arg));
        }
        drop(fs);

        if !all_alive {
            self.cleanup();
        }
    }

    /// Sends a value by reference.
    pub fn call_ref(&self, arg: &T) {
        let all_alive = self
            .fs
            .read()
            .iter()
            .map(|f| f.call(MaybeOwned::Borrowed(arg)))
            .fold(true, |a, alive| a & alive);

        if !all_alive {
            self.cleanup();
        }
    }

    /// Sends a value.
    #[inline]
    pub fn call<'a>(&self, arg: impl Into<MaybeOwned<'a, T>>)
    where
        T: 'a,
    {
        match arg.into() {
            MaybeOwned::Owned(v) => self.call_owned(v),
            MaybeOwned::Borrowed(r) => self.call_ref(r),
        }
    }

    /// Sends a value using multiple threads.
    #[cfg(feature = "crossbeam-utils")]
    pub fn call_parallel(&self, arg: &T)
    where
        T: Sync,
    {
        let fs = self.fs.read();
        let n = fs.len();
        // nothing to do
        if n == 0 {
            return;
        }
        // only 1 callback, just run it on this thread
        if n == 1 {
            if !fs[0].call(MaybeOwned::Borrowed(arg)) {
                self.cleanup();
            }
            return;
        }
        // 2+ callbacks, we need more threads
        let all_alive = AtomicBool::new(true);
        thread::scope(|scope| {
            let all_alive = &all_alive;

            let mut i = 0;
            // spawn N-1 threads
            for _ in 1..n {
                let f = &fs[i];
                scope.spawn(move |_| {
                    if !f.call(MaybeOwned::Borrowed(arg)) {
                        all_alive.store(false, Ordering::Relaxed);
                    }
                });
                i += 1;
            }
            // run the last callback on current thread
            if !fs[i].call(MaybeOwned::Borrowed(arg)) {
                all_alive.store(false, Ordering::Relaxed);
            }
        })
        .unwrap();
        // after all threads finished, continue with the cleanup
        drop(fs);
        if all_alive.load(Ordering::Relaxed) {
            self.cleanup();
        }
    }

    /// Removes the dead callbacks.
    fn cleanup(&self) {
        if let Some(mut fs) = self.fs.try_write() {
            fs.retain(FnCell::is_alive);
        }
    }

    #[cfg(test)]
    pub(crate) fn len(&self) -> usize {
        self.fs.read().len()
    }
}

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


<commit_before>use regex::Regex;
use std::env;
use std::fs::File;
use std::io::BufReader;

#[macro_use]
extern crate lazy_static;
extern crate regex;

//Maybe do not need regex
lazy_static! {
    static ref line_re: Regex = Regex::new(r"^\d ").unwrap();
    static ref symbols_re: Regex = Regex::new(r"").unwrap();
    static ref addres_re: Regex = Regex::new(r"").unwrap();
}

#[derive(Debug)]
pub enum Content {
    DefSym(Vec<String>),
    Symbols(Vec<String>),
    Addrs(Vec<String>),
}

#[derive(Debug)]
pub struct SingleLine {
    pub num: i32,
    pub content: Option<Content>,
}

impl Content {
    pub fn num_change(&mut self) -> Vec<(String, i32)> {
        let mut result: Vec<(String, i32)> = vec![];
        match self {
            Content::DefSym(l) | Content::Addrs(l) => {
                let (_, l2) = l.split_at(1);
                for (i, (x, y)) in l.iter().zip(l2.iter()).enumerate() {
                    if i % 2 == 0 {
                        result.push((x.clone(), y.parse::<i32>().unwrap()));
                    }
                }
            }
            _ => (),
        }
        return result;
    }
}

pub fn read_linker_line(li: String) -> SingleLine {
    let mut cut_str: Vec<&str> = li.split_whitespace().collect();
    let num = cut_str[0].parse::<i32>().unwrap();

    if cut_str.len() == 1 {
        return SingleLine {
            num: num,
            content: None,
        };
    }

    if cut_str[1] != "A" && cut_str[1] != "E" && cut_str[1] != "R" && cut_str[1] != "I" {
        if let Ok(_) = cut_str[2].parse::<i32>() {
            return SingleLine {
                num: num,
                content: Some(Content::DefSym(
                    cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
                )),
            };
        }
        return SingleLine {
            num: num,
            content: Some(Content::Symbols(
                cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
            )),
        };
    } else {
        return SingleLine {
            num: num,
            content: Some(Content::Addrs(
                cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
            )),
        };
    }
}

pub fn add_line_vec(ve: &mut Vec<SingleLine>, l: SingleLine) {
    ve.push(l);
}

<commit_msg>a bit<commit_after>use regex::Regex;
use std::env;
use std::fs::File;
use std::io::BufReader;
use std::collections::HashMap;

#[macro_use]
extern crate lazy_static;
extern crate regex;

//Maybe do not need regex
lazy_static! {
    static ref line_re: Regex = Regex::new(r"^\d ").unwrap();
    static ref symbols_re: Regex = Regex::new(r"").unwrap();
    static ref addres_re: Regex = Regex::new(r"").unwrap();
}

#[derive(Debug)]
pub enum Content {
    DefSym(Vec<String>),
    Symbols(Vec<String>),
    Addrs(Vec<String>),
}

#[derive(Debug)]
pub struct SingleLine {
    pub num: i32,
    pub content: Option<Content>,
}

impl Content {
    pub fn num_change(&mut self) -> Vec<(String, i32)> {
        let mut result: Vec<(String, i32)> = vec![];
        match self {
            Content::DefSym(l) | Content::Addrs(l) => {
                let (_, l2) = l.split_at(1);
                for (i, (x, y)) in l.iter().zip(l2.iter()).enumerate() {
                    if i % 2 == 0 {
                        result.push((x.clone(), y.parse::<i32>().unwrap()));
                    }
                }
            }
            _ => (),
        }
        return result;
    }
}

pub fn read_linker_line(li: String) -> SingleLine {
    let mut cut_str: Vec<&str> = li.split_whitespace().collect();
    let num = cut_str[0].parse::<i32>().unwrap();

    if cut_str.len() == 1 {
        return SingleLine {
            num: num,
            content: None,
        };
    }

    if cut_str[1] != "A" && cut_str[1] != "E" && cut_str[1] != "R" && cut_str[1] != "I" {
        if let Ok(_) = cut_str[2].parse::<i32>() {
            return SingleLine {
                num: num,
                content: Some(Content::DefSym(
                    cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
                )),
            };
        }
        return SingleLine {
            num: num,
            content: Some(Content::Symbols(
                cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
            )),
        };
    } else {
        return SingleLine {
            num: num,
            content: Some(Content::Addrs(
                cut_str.split_off(1).iter().map(|s| s.to_string()).collect(),
            )),
        };
    }
}

pub fn add_line_vec(ve: &mut Vec<SingleLine>, l: SingleLine) {
    ve.push(l);
}

fn iter_all_lines() -> (HashMap, Vec<(String,i32)>) {
    return HashMap::new(), vec![("a",1)];
}
<|endoftext|>


<commit_before>/// Worker contains all workers that do the expensive job in background.

use std::sync::Arc;
use std::thread::{self, JoinHandle, Builder};
use std::io;
use std::fmt::Display;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender, Receiver};
use std::time::Instant;
use std::result;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Stopped
        IoError(e: io::Error) {
            from()
            display("{}", e)
        }
    }
}

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

pub trait Runnable<T: Display> {
    fn run(&mut self, t: T);
}

/// A worker that can schedule time consuming tasks.
pub struct Worker<T: Display> {
    name: String,
    counter: Arc<AtomicUsize>,
    sender: Option<Sender<T>>,
    receiver: Option<Receiver<T>>,
    handle: Option<JoinHandle<()>>,
}

impl<T: Display + Send + 'static> Worker<T> {
    pub fn new(name: String) -> Worker<T> {
        let (tx, rx) = mpsc::channel();
        Worker {
            name: name,
            counter: Arc::new(AtomicUsize::new(0)),
            sender: Some(tx),
            receiver: Some(rx),
            handle: None,
        }
    }

    pub fn start<R: Runnable<T> + Send + 'static>(&mut self, mut runner: R) -> Result<()> {
        info!("starting working thread: {}", self.name);
        if self.receiver.is_none() {
            warn!("worker {} has been started.", self.name);
            return Ok(());
        }

        let rx = self.receiver.take().unwrap();
        let counter = self.counter.clone();
        let res = Builder::new().name(self.name.clone()).spawn(move || {
            loop {
                let t = rx.recv();
                if t.is_err() {
                    // no more msg will be sent.
                    return;
                }
                counter.fetch_sub(1, Ordering::SeqCst);
                let t = t.unwrap();
                let task_str = format!("{}", t);
                let timer = Instant::now();
                runner.run(t);
                // TODO maybe we need a perf logger?
                info!("task {} takes {:?} to finish.", task_str, timer.elapsed());
            }
        });
        let h = try!(res);
        self.handle = Some(h);
        Ok(())
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<()> {
        debug!("scheduling task {}", task);
        if let Some(tx) = self.sender.as_ref() {
            // receiver will be closed only when we close the sender first.
            tx.send(task).unwrap();
            self.counter.fetch_add(1, Ordering::SeqCst);
            Ok(())
        } else {
            Err(Error::Stopped)
        }
    }

    pub fn is_busy(&self) -> bool {
        self.counter.load(Ordering::SeqCst) > 0
    }

    pub fn stop(&mut self) -> thread::Result<()> {
        if self.sender.is_none() {
            return Ok(());
        }
        // close sender explictly so the background thread will exit.
        info!("stoping {}", self.name);
        drop(self.sender.take().unwrap());
        if let Some(h) = self.handle.take() {
            try!(h.join());
        }
        Ok(())
    }
}
<commit_msg>worker: use slow timer. (#484)<commit_after>/// Worker contains all workers that do the expensive job in background.

use std::sync::Arc;
use std::thread::{self, JoinHandle, Builder};
use std::io;
use std::fmt::Display;
use std::sync::atomic::{AtomicUsize, Ordering};
use std::sync::mpsc::{self, Sender, Receiver};
use std::result;

use util::SlowTimer;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Stopped
        IoError(e: io::Error) {
            from()
            display("{}", e)
        }
    }
}

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

pub trait Runnable<T: Display> {
    fn run(&mut self, t: T);
}

/// A worker that can schedule time consuming tasks.
pub struct Worker<T: Display> {
    name: String,
    counter: Arc<AtomicUsize>,
    sender: Option<Sender<T>>,
    receiver: Option<Receiver<T>>,
    handle: Option<JoinHandle<()>>,
}

impl<T: Display + Send + 'static> Worker<T> {
    pub fn new(name: String) -> Worker<T> {
        let (tx, rx) = mpsc::channel();
        Worker {
            name: name,
            counter: Arc::new(AtomicUsize::new(0)),
            sender: Some(tx),
            receiver: Some(rx),
            handle: None,
        }
    }

    pub fn start<R: Runnable<T> + Send + 'static>(&mut self, mut runner: R) -> Result<()> {
        info!("starting working thread: {}", self.name);
        if self.receiver.is_none() {
            warn!("worker {} has been started.", self.name);
            return Ok(());
        }

        let rx = self.receiver.take().unwrap();
        let counter = self.counter.clone();
        let res = Builder::new().name(self.name.clone()).spawn(move || {
            loop {
                let t = rx.recv();
                if t.is_err() {
                    // no more msg will be sent.
                    return;
                }
                counter.fetch_sub(1, Ordering::SeqCst);
                let t = t.unwrap();
                let task_str = format!("{}", t);
                let timer = SlowTimer::new();
                runner.run(t);
                slow_log!(timer,
                          "task {} takes {:?} to finish.",
                          task_str,
                          timer.elapsed());
            }
        });
        let h = try!(res);
        self.handle = Some(h);
        Ok(())
    }

    /// Schedule a task to run.
    ///
    /// If the worker is stopped, an error will return.
    pub fn schedule(&self, task: T) -> Result<()> {
        debug!("scheduling task {}", task);
        if let Some(tx) = self.sender.as_ref() {
            // receiver will be closed only when we close the sender first.
            tx.send(task).unwrap();
            self.counter.fetch_add(1, Ordering::SeqCst);
            Ok(())
        } else {
            Err(Error::Stopped)
        }
    }

    pub fn is_busy(&self) -> bool {
        self.counter.load(Ordering::SeqCst) > 0
    }

    pub fn stop(&mut self) -> thread::Result<()> {
        if self.sender.is_none() {
            return Ok(());
        }
        // close sender explictly so the background thread will exit.
        info!("stoping {}", self.name);
        drop(self.sender.take().unwrap());
        if let Some(h) = self.handle.take() {
            try!(h.join());
        }
        Ok(())
    }
}
<|endoftext|>