<commit_before>extern crate ransid;

use std::cmp;
use std::collections::{BTreeSet, VecDeque};
use std::io::Result;

use orbclient::{Color, Event, EventOption, Renderer, Window};

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory", "rdi", "rsi", "rcx"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory", "rdi", "rcx"
        : "intel", "volatile");
}

pub struct Console {
    pub console: ransid::Console,
    pub window: Window,
    pub changed: BTreeSet<usize>,
    pub ctrl: bool,
    pub input: Vec<u8>,
    pub end_of_input: bool,
    pub cooked: VecDeque<u8>,
    pub requested: usize
}

impl Console {
    pub fn new(width: u32, height: u32) -> Console {
        let mut window = Window::new_flags(-1, -1, width, height, "Terminal", true).unwrap();
        window.sync();
        Console {
            console: ransid::Console::new(width as usize / 8, height as usize / 16),
            window: window,
            changed: BTreeSet::new(),
            ctrl: false,
            input: Vec::new(),
            end_of_input: false,
            cooked: VecDeque::new(),
            requested: 0
        }
    }

    pub fn input(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                let mut buf = vec![];

                if key_event.scancode == 0x1D {
                    self.ctrl = key_event.pressed;
                } else if key_event.pressed {
                    match key_event.scancode {
                        0x0E => { // Backspace
                            buf.extend_from_slice(b"\x7F");
                        },
                        0x1C => { // Enter
                            buf.extend_from_slice(b"\r");
                        }
                        0x47 => { // Home
                            buf.extend_from_slice(b"\x1B[H");
                        },
                        0x48 => { // Up
                            buf.extend_from_slice(b"\x1B[A");
                        },
                        0x49 => { // Page up
                            buf.extend_from_slice(b"\x1B[5~");
                        },
                        0x4B => { // Left
                            buf.extend_from_slice(b"\x1B[D");
                        },
                        0x4D => { // Right
                            buf.extend_from_slice(b"\x1B[C");
                        },
                        0x4F => { // End
                            buf.extend_from_slice(b"\x1B[F");
                        },
                        0x50 => { // Down
                            buf.extend_from_slice(b"\x1B[B");
                        },
                        0x51 => { // Page down
                            buf.extend_from_slice(b"\x1B[6~");
                        },
                        0x52 => { // Insert
                            buf.extend_from_slice(b"\x1B[2~");
                        },
                        0x53 => { // Delete
                            buf.extend_from_slice(b"\x1B[3~");
                        },
                        _ => {
                            let c = match key_event.character {
                                c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
                                c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
                                c => c
                            };

                            if c != '\0' {
                                buf.extend_from_slice(&[c as u8]);
                            }
                        }
                    }
                }

                if self.console.raw_mode {
                    for &b in buf.iter() {
                        self.input.push(b);
                    }
                } else {
                    for &b in buf.iter() {
                        match b {
                            b'\x03' => {
                                self.end_of_input = true;
                                let _ = self.write(b"^C\n", true);
                            },
                            b'\x08' | b'\x7F' => {
                                if let Some(_c) = self.cooked.pop_back() {
                                    let _ = self.write(b"\x08", true);
                                }
                            },
                            b'\x1B' => {
                                let _ = self.write(b"^[", true);
                            },
                            b'\n' | b'\r' => {
                                self.cooked.push_back(b);
                                while let Some(c) = self.cooked.pop_front() {
                                    self.input.push(c);
                                }
                                let _ = self.write(b"\n", true);
                            },
                            _ => {
                                self.cooked.push_back(b);
                                let _ = self.write(&[b], true);
                            }
                        }
                    }
                }
            },
            _ => () //TODO: Mouse in terminal
        }
    }

    pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
        let width = self.window.width() as usize;
        let height = self.window.height() as usize;

        let start_y = cmp::min(height - 1, y);
        let end_y = cmp::min(height, y + h);

        let start_x = cmp::min(width - 1, x);
        let len = cmp::min(width, x + w) - start_x;

        let mut offscreen_ptr = self.window.data_mut().as_mut_ptr() as usize;

        let stride = width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            let mut row_ptr = offscreen_ptr;
            let mut cols = len;
            while cols > 0 {
                unsafe {
                    let color = *(row_ptr as *mut u32);
                    *(row_ptr as *mut u32) = !color;
                }
                row_ptr += 4;
                cols -= 1;
            }
            offscreen_ptr += stride;
            rows -= 1;
        }
    }

    pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y);
        }

        {
            let window = &mut self.window;
            let changed = &mut self.changed;
            self.console.write(buf, |event| {
                match event {
                    ransid::Event::Char { x, y, c, color, .. } => {
                        window.char(x as i32 * 8, y as i32 * 16, c, Color { data: color.data });/*, bold, false);*/
                        changed.insert(y);
                    },
                    ransid::Event::Rect { x, y, w, h, color } => {
                        window.rect(x as i32 * 8, y as i32 * 16, w as u32 * 8, h as u32 * 16, Color { data: color.data });
                        for y2 in y..y + h {
                            changed.insert(y2);
                        }
                    },
                    ransid::Event::Scroll { rows, color } => {
                        let rows = rows as u32 * 16;
                        let data = (color.data as u64) << 32 | color.data as u64;

                        let width = window.width()/2;
                        let height = window.height();
                        if rows > 0 && rows < height {
                            let off1 = rows * width;
                            let off2 = height * width - off1;
                            unsafe {
                                let data_ptr = window.data_mut().as_mut_ptr() as *mut u64;
                                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2 as usize);
                                fast_set64(data_ptr.offset(off2 as isize), data, off1 as usize);
                            }
                        }

                        for y in 0..window.height()/16 {
                            changed.insert(y as usize);
                        }
                    }
                }
            });
        }

        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y as usize);
        }

        if ! self.console.raw_mode && sync {
            self.sync();
        }

        Ok(buf.len())
    }

    fn sync(&mut self) {
        /*
        let width = self.window.width;
        for change in self.changed.iter() {
            self.display.sync(0, change * 16, width, 16);
        }
        */
        if ! self.changed.is_empty() {
            self.window.sync();
        }
        self.changed.clear();
    }

    pub fn redraw(&mut self) {
        /*
        let width = self.window.width;
        let height = self.window.height;
        */
        self.window.sync();
        self.changed.clear();
    }
}
<commit_msg>Terminal: Do not invert alpha channel<commit_after>extern crate ransid;

use std::cmp;
use std::collections::{BTreeSet, VecDeque};
use std::io::Result;

use orbclient::{Color, Event, EventOption, Renderer, Window};

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_copy64(dst: *mut u64, src: *const u64, len: usize) {
    asm!("cld
        rep movsq"
        :
        : "{rdi}"(dst as usize), "{rsi}"(src as usize), "{rcx}"(len)
        : "cc", "memory", "rdi", "rsi", "rcx"
        : "intel", "volatile");
}

#[cfg(target_arch = "x86_64")]
#[inline(always)]
#[cold]
pub unsafe fn fast_set64(dst: *mut u64, src: u64, len: usize) {
    asm!("cld
        rep stosq"
        :
        : "{rdi}"(dst as usize), "{rax}"(src), "{rcx}"(len)
        : "cc", "memory", "rdi", "rcx"
        : "intel", "volatile");
}

pub struct Console {
    pub console: ransid::Console,
    pub window: Window,
    pub changed: BTreeSet<usize>,
    pub ctrl: bool,
    pub input: Vec<u8>,
    pub end_of_input: bool,
    pub cooked: VecDeque<u8>,
    pub requested: usize
}

impl Console {
    pub fn new(width: u32, height: u32) -> Console {
        let mut window = Window::new_flags(-1, -1, width, height, "Terminal", true).unwrap();
        window.sync();
        Console {
            console: ransid::Console::new(width as usize / 8, height as usize / 16),
            window: window,
            changed: BTreeSet::new(),
            ctrl: false,
            input: Vec::new(),
            end_of_input: false,
            cooked: VecDeque::new(),
            requested: 0
        }
    }

    pub fn input(&mut self, event: &Event) {
        match event.to_option() {
            EventOption::Key(key_event) => {
                let mut buf = vec![];

                if key_event.scancode == 0x1D {
                    self.ctrl = key_event.pressed;
                } else if key_event.pressed {
                    match key_event.scancode {
                        0x0E => { // Backspace
                            buf.extend_from_slice(b"\x7F");
                        },
                        0x1C => { // Enter
                            buf.extend_from_slice(b"\r");
                        }
                        0x47 => { // Home
                            buf.extend_from_slice(b"\x1B[H");
                        },
                        0x48 => { // Up
                            buf.extend_from_slice(b"\x1B[A");
                        },
                        0x49 => { // Page up
                            buf.extend_from_slice(b"\x1B[5~");
                        },
                        0x4B => { // Left
                            buf.extend_from_slice(b"\x1B[D");
                        },
                        0x4D => { // Right
                            buf.extend_from_slice(b"\x1B[C");
                        },
                        0x4F => { // End
                            buf.extend_from_slice(b"\x1B[F");
                        },
                        0x50 => { // Down
                            buf.extend_from_slice(b"\x1B[B");
                        },
                        0x51 => { // Page down
                            buf.extend_from_slice(b"\x1B[6~");
                        },
                        0x52 => { // Insert
                            buf.extend_from_slice(b"\x1B[2~");
                        },
                        0x53 => { // Delete
                            buf.extend_from_slice(b"\x1B[3~");
                        },
                        _ => {
                            let c = match key_event.character {
                                c @ 'A' ... 'Z' if self.ctrl => ((c as u8 - b'A') + b'\x01') as char,
                                c @ 'a' ... 'z' if self.ctrl => ((c as u8 - b'a') + b'\x01') as char,
                                c => c
                            };

                            if c != '\0' {
                                buf.extend_from_slice(&[c as u8]);
                            }
                        }
                    }
                }

                if self.console.raw_mode {
                    for &b in buf.iter() {
                        self.input.push(b);
                    }
                } else {
                    for &b in buf.iter() {
                        match b {
                            b'\x03' => {
                                self.end_of_input = true;
                                let _ = self.write(b"^C\n", true);
                            },
                            b'\x08' | b'\x7F' => {
                                if let Some(_c) = self.cooked.pop_back() {
                                    let _ = self.write(b"\x08", true);
                                }
                            },
                            b'\x1B' => {
                                let _ = self.write(b"^[", true);
                            },
                            b'\n' | b'\r' => {
                                self.cooked.push_back(b);
                                while let Some(c) = self.cooked.pop_front() {
                                    self.input.push(c);
                                }
                                let _ = self.write(b"\n", true);
                            },
                            _ => {
                                self.cooked.push_back(b);
                                let _ = self.write(&[b], true);
                            }
                        }
                    }
                }
            },
            _ => () //TODO: Mouse in terminal
        }
    }

    pub fn invert(&mut self, x: usize, y: usize, w: usize, h: usize) {
        let width = self.window.width() as usize;
        let height = self.window.height() as usize;

        let start_y = cmp::min(height - 1, y);
        let end_y = cmp::min(height, y + h);

        let start_x = cmp::min(width - 1, x);
        let len = cmp::min(width, x + w) - start_x;

        let mut offscreen_ptr = self.window.data_mut().as_mut_ptr() as usize;

        let stride = width * 4;

        let offset = y * stride + start_x * 4;
        offscreen_ptr += offset;

        let mut rows = end_y - start_y;
        while rows > 0 {
            let mut row_ptr = offscreen_ptr;
            let mut cols = len;
            while cols > 0 {
                unsafe {
                    let color = *(row_ptr as *mut u32);
                    *(row_ptr as *mut u32) = color ^ 0x00FFFFFF;
                }
                row_ptr += 4;
                cols -= 1;
            }
            offscreen_ptr += stride;
            rows -= 1;
        }
    }

    pub fn write(&mut self, buf: &[u8], sync: bool) -> Result<usize> {
        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y);
        }

        {
            let window = &mut self.window;
            let changed = &mut self.changed;
            self.console.write(buf, |event| {
                match event {
                    ransid::Event::Char { x, y, c, color, .. } => {
                        window.char(x as i32 * 8, y as i32 * 16, c, Color { data: color.data });/*, bold, false);*/
                        changed.insert(y);
                    },
                    ransid::Event::Rect { x, y, w, h, color } => {
                        window.rect(x as i32 * 8, y as i32 * 16, w as u32 * 8, h as u32 * 16, Color { data: color.data });
                        for y2 in y..y + h {
                            changed.insert(y2);
                        }
                    },
                    ransid::Event::Scroll { rows, color } => {
                        let rows = rows as u32 * 16;
                        let data = (color.data as u64) << 32 | color.data as u64;

                        let width = window.width()/2;
                        let height = window.height();
                        if rows > 0 && rows < height {
                            let off1 = rows * width;
                            let off2 = height * width - off1;
                            unsafe {
                                let data_ptr = window.data_mut().as_mut_ptr() as *mut u64;
                                fast_copy64(data_ptr, data_ptr.offset(off1 as isize), off2 as usize);
                                fast_set64(data_ptr.offset(off2 as isize), data, off1 as usize);
                            }
                        }

                        for y in 0..window.height()/16 {
                            changed.insert(y as usize);
                        }
                    }
                }
            });
        }

        if self.console.cursor && self.console.x < self.console.w && self.console.y < self.console.h {
            let x = self.console.x;
            let y = self.console.y;
            self.invert(x * 8, y * 16, 8, 16);
            self.changed.insert(y as usize);
        }

        if ! self.console.raw_mode && sync {
            self.sync();
        }

        Ok(buf.len())
    }

    fn sync(&mut self) {
        /*
        let width = self.window.width;
        for change in self.changed.iter() {
            self.display.sync(0, change * 16, width, 16);
        }
        */
        if ! self.changed.is_empty() {
            self.window.sync();
        }
        self.changed.clear();
    }

    pub fn redraw(&mut self) {
        /*
        let width = self.window.width;
        let height = self.window.height;
        */
        self.window.sync();
        self.changed.clear();
    }
}
<|endoftext|>


<commit_before>use bytes::Buf;
use futures_core::stream::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf};

pin_project! {
    /// Convert a [`Stream`] of byte chunks into an [`AsyncRead`].
    ///
    /// This type performs the inverse operation of [`ReaderStream`].
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use tokio::io::{AsyncReadExt, Result};
    /// use tokio_util::io::StreamReader;
    /// # #[tokio::main]
    /// # async fn main() -> std::io::Result<()> {
    ///
    /// // Create a stream from an iterator.
    /// let stream = tokio_stream::iter(vec![
    ///     Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
    ///     Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
    ///     Result::Ok(Bytes::from_static(&[8, 9, 10, 11])),
    /// ]);
    ///
    /// // Convert it to an AsyncRead.
    /// let mut read = StreamReader::new(stream);
    ///
    /// // Read five bytes from the stream.
    /// let mut buf = [0; 5];
    /// read.read_exact(&mut buf).await?;
    /// assert_eq!(buf, [0, 1, 2, 3, 4]);
    ///
    /// // Read the rest of the current chunk.
    /// assert_eq!(read.read(&mut buf).await?, 3);
    /// assert_eq!(&buf[..3], [5, 6, 7]);
    ///
    /// // Read the next chunk.
    /// assert_eq!(read.read(&mut buf).await?, 4);
    /// assert_eq!(&buf[..4], [8, 9, 10, 11]);
    ///
    /// // We have now reached the end.
    /// assert_eq!(read.read(&mut buf).await?, 0);
    ///
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`AsyncRead`]: tokio::io::AsyncRead
    /// [`Stream`]: futures_core::Stream
    /// [`ReaderStream`]: crate::io::ReaderStream
    #[derive(Debug)]
    pub struct StreamReader<S, B> {
        #[pin]
        inner: S,
        chunk: Option<B>,
    }
}

impl<S, B, E> StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    /// Convert a stream of byte chunks into an [`AsyncRead`](tokio::io::AsyncRead).
    ///
    /// The item should be a [`Result`] with the ok variant being something that
    /// implements the [`Buf`] trait (e.g. `Vec<u8>` or `Bytes`). The error
    /// should be convertible into an [io error].
    ///
    /// [`Result`]: std::result::Result
    /// [`Buf`]: bytes::Buf
    /// [io error]: std::io::Error
    pub fn new(stream: S) -> Self {
        Self {
            inner: stream,
            chunk: None,
        }
    }

    /// Do we have a chunk and is it non-empty?
    fn has_chunk(self: Pin<&mut Self>) -> bool {
        if let Some(chunk) = self.project().chunk {
            chunk.remaining() > 0
        } else {
            false
        }
    }
}

impl<S, B> StreamReader<S, B> {
    /// Gets a reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_ref(&self) -> &S {
        &self.inner
    }

    /// Gets a mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_mut(&mut self) -> &mut S {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
        self.project().inner
    }

    /// Consumes this `BufWriter`, returning the underlying stream.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    pub fn into_inner(self) -> S {
        self.inner
    }
}

impl<S, B, E> AsyncRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        if buf.remaining() == 0 {
            return Poll::Ready(Ok(()));
        }

        let inner_buf = match self.as_mut().poll_fill_buf(cx) {
            Poll::Ready(Ok(buf)) => buf,
            Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
            Poll::Pending => return Poll::Pending,
        };
        let len = std::cmp::min(inner_buf.len(), buf.remaining());
        buf.put_slice(&inner_buf[..len]);

        self.consume(len);
        Poll::Ready(Ok(()))
    }
}

impl<S, B, E> AsyncBufRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        loop {
            if self.as_mut().has_chunk() {
                // This unwrap is very sad, but it can't be avoided.
                let buf = self.project().chunk.as_ref().unwrap().chunk();
                return Poll::Ready(Ok(buf));
            } else {
                match self.as_mut().project().inner.poll_next(cx) {
                    Poll::Ready(Some(Ok(chunk))) => {
                        // Go around the loop in case the chunk is empty.
                        *self.as_mut().project().chunk = Some(chunk);
                    }
                    Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
                    Poll::Ready(None) => return Poll::Ready(Ok(&[])),
                    Poll::Pending => return Poll::Pending,
                }
            }
        }
    }
    fn consume(self: Pin<&mut Self>, amt: usize) {
        if amt > 0 {
            self.project()
                .chunk
                .as_mut()
                .expect("No chunk present")
                .advance(amt);
        }
    }
}
<commit_msg>io: add `StreamReader::into_inner_with_chunk` (#4559)<commit_after>use bytes::Buf;
use futures_core::stream::Stream;
use pin_project_lite::pin_project;
use std::io;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::{AsyncBufRead, AsyncRead, ReadBuf};

pin_project! {
    /// Convert a [`Stream`] of byte chunks into an [`AsyncRead`].
    ///
    /// This type performs the inverse operation of [`ReaderStream`].
    ///
    /// # Example
    ///
    /// ```
    /// use bytes::Bytes;
    /// use tokio::io::{AsyncReadExt, Result};
    /// use tokio_util::io::StreamReader;
    /// # #[tokio::main]
    /// # async fn main() -> std::io::Result<()> {
    ///
    /// // Create a stream from an iterator.
    /// let stream = tokio_stream::iter(vec![
    ///     Result::Ok(Bytes::from_static(&[0, 1, 2, 3])),
    ///     Result::Ok(Bytes::from_static(&[4, 5, 6, 7])),
    ///     Result::Ok(Bytes::from_static(&[8, 9, 10, 11])),
    /// ]);
    ///
    /// // Convert it to an AsyncRead.
    /// let mut read = StreamReader::new(stream);
    ///
    /// // Read five bytes from the stream.
    /// let mut buf = [0; 5];
    /// read.read_exact(&mut buf).await?;
    /// assert_eq!(buf, [0, 1, 2, 3, 4]);
    ///
    /// // Read the rest of the current chunk.
    /// assert_eq!(read.read(&mut buf).await?, 3);
    /// assert_eq!(&buf[..3], [5, 6, 7]);
    ///
    /// // Read the next chunk.
    /// assert_eq!(read.read(&mut buf).await?, 4);
    /// assert_eq!(&buf[..4], [8, 9, 10, 11]);
    ///
    /// // We have now reached the end.
    /// assert_eq!(read.read(&mut buf).await?, 0);
    ///
    /// # Ok(())
    /// # }
    /// ```
    ///
    /// [`AsyncRead`]: tokio::io::AsyncRead
    /// [`Stream`]: futures_core::Stream
    /// [`ReaderStream`]: crate::io::ReaderStream
    #[derive(Debug)]
    pub struct StreamReader<S, B> {
        #[pin]
        inner: S,
        chunk: Option<B>,
    }
}

impl<S, B, E> StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    /// Convert a stream of byte chunks into an [`AsyncRead`](tokio::io::AsyncRead).
    ///
    /// The item should be a [`Result`] with the ok variant being something that
    /// implements the [`Buf`] trait (e.g. `Vec<u8>` or `Bytes`). The error
    /// should be convertible into an [io error].
    ///
    /// [`Result`]: std::result::Result
    /// [`Buf`]: bytes::Buf
    /// [io error]: std::io::Error
    pub fn new(stream: S) -> Self {
        Self {
            inner: stream,
            chunk: None,
        }
    }

    /// Do we have a chunk and is it non-empty?
    fn has_chunk(&self) -> bool {
        if let Some(ref chunk) = self.chunk {
            chunk.remaining() > 0
        } else {
            false
        }
    }

    /// Consumes this `StreamReader`, returning a Tuple consisting
    /// of the underlying stream and an Option of the interal buffer,
    /// which is Some in case the buffer contains elements.
    pub fn into_inner_with_chunk(self) -> (S, Option<B>) {
        if self.has_chunk() {
            (self.inner, self.chunk)
        } else {
            (self.inner, None)
        }
    }
}

impl<S, B> StreamReader<S, B> {
    /// Gets a reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_ref(&self) -> &S {
        &self.inner
    }

    /// Gets a mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_mut(&mut self) -> &mut S {
        &mut self.inner
    }

    /// Gets a pinned mutable reference to the underlying stream.
    ///
    /// It is inadvisable to directly read from the underlying stream.
    pub fn get_pin_mut(self: Pin<&mut Self>) -> Pin<&mut S> {
        self.project().inner
    }

    /// Consumes this `BufWriter`, returning the underlying stream.
    ///
    /// Note that any leftover data in the internal buffer is lost.
    /// If you additionally want access to the internal buffer use
    /// [`into_inner_with_chunk`].
    ///
    /// [`into_inner_with_chunk`]: crate::io::StreamReader::into_inner_with_chunk
    pub fn into_inner(self) -> S {
        self.inner
    }
}

impl<S, B, E> AsyncRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_read(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &mut ReadBuf<'_>,
    ) -> Poll<io::Result<()>> {
        if buf.remaining() == 0 {
            return Poll::Ready(Ok(()));
        }

        let inner_buf = match self.as_mut().poll_fill_buf(cx) {
            Poll::Ready(Ok(buf)) => buf,
            Poll::Ready(Err(err)) => return Poll::Ready(Err(err)),
            Poll::Pending => return Poll::Pending,
        };
        let len = std::cmp::min(inner_buf.len(), buf.remaining());
        buf.put_slice(&inner_buf[..len]);

        self.consume(len);
        Poll::Ready(Ok(()))
    }
}

impl<S, B, E> AsyncBufRead for StreamReader<S, B>
where
    S: Stream<Item = Result<B, E>>,
    B: Buf,
    E: Into<std::io::Error>,
{
    fn poll_fill_buf(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&[u8]>> {
        loop {
            if self.as_mut().has_chunk() {
                // This unwrap is very sad, but it can't be avoided.
                let buf = self.project().chunk.as_ref().unwrap().chunk();
                return Poll::Ready(Ok(buf));
            } else {
                match self.as_mut().project().inner.poll_next(cx) {
                    Poll::Ready(Some(Ok(chunk))) => {
                        // Go around the loop in case the chunk is empty.
                        *self.as_mut().project().chunk = Some(chunk);
                    }
                    Poll::Ready(Some(Err(err))) => return Poll::Ready(Err(err.into())),
                    Poll::Ready(None) => return Poll::Ready(Ok(&[])),
                    Poll::Pending => return Poll::Pending,
                }
            }
        }
    }
    fn consume(self: Pin<&mut Self>, amt: usize) {
        if amt > 0 {
            self.project()
                .chunk
                .as_mut()
                .expect("No chunk present")
                .advance(amt);
        }
    }
}
<|endoftext|>


<commit_before>//! The `pact_verifier` crate provides a number of exported functions using C bindings for
//! controlling the pact verification process. These can be used in any language that supports C bindings.

#![warn(missing_docs)]

use std::ffi::{CStr, CString};
use std::panic::catch_unwind;

use anyhow::Context;
use libc::{c_char, c_int, c_ushort, EXIT_FAILURE};
use log::*;
use std::env;

use crate::{as_mut, ffi_fn, safe_str};
use crate::util::*;
use crate::util::string::if_null;
use serde::Serialize;

mod args;
pub mod verifier;
pub mod handle;

/// External interface to verifier a provider
///
/// * `args` - the same as the CLI interface, except newline delimited
///
/// # Errors
///
/// Errors are returned as non-zero numeric values.
///
/// | Error | Description |
/// |-------|-------------|
/// | 1 | The verification process failed, see output for errors |
/// | 2 | A null pointer was received |
/// | 3 | The method panicked |
/// | 4 | Invalid arguments were provided to the verification process |
///
/// # Safety
///
/// Exported functions are inherently unsafe. Deal.
#[no_mangle]
pub unsafe extern fn pactffi_verify(args: *const c_char) -> i32 {
  if args.is_null() {
    return 2;
  }

  let result = catch_unwind(|| {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(async {
      let args_raw = CStr::from_ptr(args).to_string_lossy().into_owned();
      let args: Vec<String> = args_raw.lines().map(|s| s.to_string()).collect();
      let result = verifier::handle_args(args).await;

      match result {
        Ok(_) => 0,
        Err(e) => e
      }
    })
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      3
    }
  }
}

ffi_fn! {
    /// Get a Handle to a newly created verifier. You should call `pactffi_verifier_shutdown` when
    /// done with the verifier to free all allocated resources
    ///
    /// # Safety
    ///
    /// This function is safe.
    ///
    /// # Error Handling
    ///
    /// Returns NULL on error.
    fn pactffi_verifier_new() -> *mut handle::VerifierHandle {
        let handle = handle::VerifierHandle::new();
        ptr::raw_to(handle)
    } {
        ptr::null_mut_to::<handle::VerifierHandle>()
    }
}

ffi_fn! {
    /// Shutdown the verifier and release all resources
    fn pactffi_verifier_shutdown(handle: *mut handle::VerifierHandle) {
        ptr::drop_raw(handle);
    }
}

ffi_fn! {
    /// Set the provider details for the Pact verifier. Passing a NULL for any field will
    /// use the default value for that field.
    ///
    /// # Safety
    ///
    /// All string fields must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    fn pactffi_verifier_set_provider_info(
      handle: *mut handle::VerifierHandle,
      name: *const c_char,
      scheme: *const c_char,
      host: *const c_char,
      port: c_ushort,
      path: *const c_char
    ) {
      let handle = as_mut!(handle);
      let name = if_null(name, "provider");
      let scheme = if_null(scheme, "http");
      let host = if_null(host, "localhost");
      let path = if_null(path, "/");

      handle.update_provider_info(name, scheme, host, port as u16, path);
    }
}

ffi_fn! {
    /// Adds a Pact file as a source to verify.
    ///
    /// # Safety
    ///
    /// All string fields must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    fn pactffi_verifier_add_file_source(
      handle: *mut handle::VerifierHandle,
      file: *const c_char
    ) {
      let handle = as_mut!(handle);
      let file = safe_str!(file);

      handle.add_file_source(file);
    }
}

ffi_fn! {
    /// Runs the verification.
    ///
    /// # Error Handling
    ///
    /// Errors will be reported with a non-zero return value.
    fn pactffi_verifier_execute(handle: *mut handle::VerifierHandle) -> c_int {
      let handle = as_mut!(handle);

      handle.execute()
    } {
      EXIT_FAILURE
    }
}

#[derive(Serialize)]
struct Argument {
    name: Option<String>,
    short: Option<String>,
    long: Option<String>,
    help: Option<String>,
}

/// External interface to retrieve the options and arguments available when calling the CLI interface,
/// returning them as a JSON string.
///
/// The purpose is to then be able to use in other languages which wrap the FFI library, to implement
/// the same CLI functionality automatically without manual maintenance of arguments, help descriptions
/// etc.
///
/// # Example structure
/// ```json
/// [
///     {
///         "name": "broker-url",
///         "short": "b",
///         "long": "broker-url",
///         "help": "URL of the pact broker to fetch pacts from to verify (requires the provider name parameter)"
///     },
///     {
///         "name": "port",
///         "short": "p",
///         "long": "port",
///         "help": "Provider port (defaults to protocol default 80/443)"
///     },
///     {
///         "name": "user",
///         "short": null,
///         "long": "user",
///         "help": "Username to use when fetching pacts from URLS"
///     }
/// ]
/// ```
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub extern "C" fn pactffi_verifier_cli_args() -> *const c_char {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let app = args::setup_app(program, clap::crate_version!());

    // Iterate through the args, extracting info from each to then add to a Vector of args
    let mut args: Vec<Argument> = Vec::new();
    for opt in app.p.opts.iter() {
        let mut arg = Argument { name: None, short: None, long: None, help: None };

        // Name
        // TODO: Maybe superfluous as this is always the same as the long
        let arg_name = opt.b.name;
        arg.name = Some(arg_name.to_string());

        // Short
        match opt.s.short {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let short = c_str.to_str().unwrap();
                arg.short = Some(short.to_string());
            }
        }

        // Long
        match opt.s.long {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let long = c_str.to_str().unwrap();
                arg.long = Some(long.to_string());
            }
        }

        // Help
        match opt.b.help {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let help = c_str.to_str().unwrap();
                arg.help = Some(help.to_string());
            }
        }

        args.push(arg);
    }

    let json = serde_json::to_string(&args).unwrap();
    let c_str = CString::new(json).unwrap();
    c_str.into_raw() as *const c_char
}<commit_msg>feat(ffi verifier): add possible_values<commit_after>//! The `pact_verifier` crate provides a number of exported functions using C bindings for
//! controlling the pact verification process. These can be used in any language that supports C bindings.

#![warn(missing_docs)]

use std::ffi::{CStr, CString};
use std::panic::catch_unwind;

use anyhow::Context;
use libc::{c_char, c_int, c_ushort, EXIT_FAILURE};
use log::*;
use std::env;

use crate::{as_mut, ffi_fn, safe_str};
use crate::util::*;
use crate::util::string::if_null;
use serde::Serialize;

mod args;
pub mod verifier;
pub mod handle;

/// External interface to verifier a provider
///
/// * `args` - the same as the CLI interface, except newline delimited
///
/// # Errors
///
/// Errors are returned as non-zero numeric values.
///
/// | Error | Description |
/// |-------|-------------|
/// | 1 | The verification process failed, see output for errors |
/// | 2 | A null pointer was received |
/// | 3 | The method panicked |
/// | 4 | Invalid arguments were provided to the verification process |
///
/// # Safety
///
/// Exported functions are inherently unsafe. Deal.
#[no_mangle]
pub unsafe extern fn pactffi_verify(args: *const c_char) -> i32 {
  if args.is_null() {
    return 2;
  }

  let result = catch_unwind(|| {
    let runtime = tokio::runtime::Runtime::new().unwrap();
    runtime.block_on(async {
      let args_raw = CStr::from_ptr(args).to_string_lossy().into_owned();
      let args: Vec<String> = args_raw.lines().map(|s| s.to_string()).collect();
      let result = verifier::handle_args(args).await;

      match result {
        Ok(_) => 0,
        Err(e) => e
      }
    })
  });

  match result {
    Ok(val) => val,
    Err(cause) => {
      log::error!("Caught a general panic: {:?}", cause);
      3
    }
  }
}

ffi_fn! {
    /// Get a Handle to a newly created verifier. You should call `pactffi_verifier_shutdown` when
    /// done with the verifier to free all allocated resources
    ///
    /// # Safety
    ///
    /// This function is safe.
    ///
    /// # Error Handling
    ///
    /// Returns NULL on error.
    fn pactffi_verifier_new() -> *mut handle::VerifierHandle {
        let handle = handle::VerifierHandle::new();
        ptr::raw_to(handle)
    } {
        ptr::null_mut_to::<handle::VerifierHandle>()
    }
}

ffi_fn! {
    /// Shutdown the verifier and release all resources
    fn pactffi_verifier_shutdown(handle: *mut handle::VerifierHandle) {
        ptr::drop_raw(handle);
    }
}

ffi_fn! {
    /// Set the provider details for the Pact verifier. Passing a NULL for any field will
    /// use the default value for that field.
    ///
    /// # Safety
    ///
    /// All string fields must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    fn pactffi_verifier_set_provider_info(
      handle: *mut handle::VerifierHandle,
      name: *const c_char,
      scheme: *const c_char,
      host: *const c_char,
      port: c_ushort,
      path: *const c_char
    ) {
      let handle = as_mut!(handle);
      let name = if_null(name, "provider");
      let scheme = if_null(scheme, "http");
      let host = if_null(host, "localhost");
      let path = if_null(path, "/");

      handle.update_provider_info(name, scheme, host, port as u16, path);
    }
}

ffi_fn! {
    /// Adds a Pact file as a source to verify.
    ///
    /// # Safety
    ///
    /// All string fields must contain valid UTF-8. Invalid UTF-8
    /// will be replaced with U+FFFD REPLACEMENT CHARACTER.
    ///
    fn pactffi_verifier_add_file_source(
      handle: *mut handle::VerifierHandle,
      file: *const c_char
    ) {
      let handle = as_mut!(handle);
      let file = safe_str!(file);

      handle.add_file_source(file);
    }
}

ffi_fn! {
    /// Runs the verification.
    ///
    /// # Error Handling
    ///
    /// Errors will be reported with a non-zero return value.
    fn pactffi_verifier_execute(handle: *mut handle::VerifierHandle) -> c_int {
      let handle = as_mut!(handle);

      handle.execute()
    } {
      EXIT_FAILURE
    }
}

#[derive(Serialize)]
struct Argument {
    name: Option<String>,
    short: Option<String>,
    long: Option<String>,
    help: Option<String>,
    possible_values: Option<Vec<String>>
}

/// External interface to retrieve the options and arguments available when calling the CLI interface,
/// returning them as a JSON string.
///
/// The purpose is to then be able to use in other languages which wrap the FFI library, to implement
/// the same CLI functionality automatically without manual maintenance of arguments, help descriptions
/// etc.
///
/// # Example structure
/// ```json
/// [
///     {
///         "name": "broker-url",
///         "short": "b",
///         "long": "broker-url",
///         "help": "URL of the pact broker to fetch pacts from to verify (requires the provider name parameter)"
///     },
///     {
///         "name": "port",
///         "short": "p",
///         "long": "port",
///         "help": "Provider port (defaults to protocol default 80/443)"
///     },
///     {
///         "name": "user",
///         "short": null,
///         "long": "user",
///         "help": "Username to use when fetching pacts from URLS"
///     }
/// ]
/// ```
///
/// # Safety
///
/// Exported functions are inherently unsafe.
#[no_mangle]
pub extern "C" fn pactffi_verifier_cli_args() -> *const c_char {
    let args: Vec<String> = env::args().collect();
    let program = args[0].clone();
    let app = args::setup_app(program, clap::crate_version!());

    // Iterate through the args, extracting info from each to then add to a Vector of args
    let mut args: Vec<Argument> = Vec::new();
    for opt in app.p.opts.iter() {
        let mut arg = Argument { name: None, short: None, long: None, help: None, possible_values: None };

        // Name
        // TODO: Maybe superfluous as this is always the same as the long
        let arg_name = opt.b.name;
        arg.name = Some(arg_name.to_string());

        // Short
        match opt.s.short {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let short = c_str.to_str().unwrap();
                arg.short = Some(short.to_string());
            }
        }

        // Long
        match opt.s.long {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let long = c_str.to_str().unwrap();
                arg.long = Some(long.to_string());
            }
        }

        // Help
        match opt.b.help {
            None => {}
            Some(_val) => {
                let c_str = CString::new(_val.to_string()).unwrap();
                let help = c_str.to_str().unwrap();
                arg.help = Some(help.to_string());
            }
        }

        // Possible Values
        match opt.v.possible_vals {
            None => {}
            Some(_) => {
                let mut possible_vals: Vec<String> = Vec::new();
                let possible_values = opt.v.possible_vals.clone().unwrap();
                for possible_val in possible_values.iter() {
                    possible_vals.push(possible_val.to_string())
                }
                arg.possible_values = Some(possible_vals);
            }
        }

        args.push(arg);
    }

    let json = serde_json::to_string(&args).unwrap();
    let c_str = CString::new(json).unwrap();
    c_str.into_raw() as *const c_char
}<|endoftext|>


<commit_before>#![feature(unsafe_block_in_unsafe_fn)]
#![warn(unsafe_op_in_unsafe_fn)]
#![deny(unused_unsafe)]

unsafe fn unsf() {}

unsafe fn foo() {
    unsf();
    //~^ WARNING call to unsafe function is unsafe and requires unsafe block
}

unsafe fn bar() {
    unsafe { unsf() } // no error
}

unsafe fn baz() {
    unsafe { unsafe { unsf() } }
    //~^ ERROR unnecessary `unsafe` block
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe fn qux() {
    unsf(); // no error

    unsafe { unsf() }
    //~^ ERROR unnecessary `unsafe` block
}

fn main() {
    unsf()
    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
}
<commit_msg>Add more cases to the test<commit_after>#![feature(unsafe_block_in_unsafe_fn)]
#![warn(unsafe_op_in_unsafe_fn)]
#![deny(unused_unsafe)]
#![deny(safe_packed_borrows)]

unsafe fn unsf() {}
const PTR: *const () = std::ptr::null();
static mut VOID: () = ();

#[repr(packed)]
pub struct Packed {
    data: &'static u32,
}

const PACKED: Packed = Packed { data: &0 };

unsafe fn foo() {
    unsf();
    //~^ WARNING call to unsafe function is unsafe and requires unsafe block
    *PTR;
    //~^ WARNING dereference of raw pointer is unsafe and requires unsafe block
    VOID = ();
    //~^ WARNING use of mutable static is unsafe and requires unsafe block
    &PACKED.data; // the level for the `safe_packed_borrows` lint is ignored
    //~^ WARNING borrow of packed field is unsafe and requires unsafe block
}

unsafe fn bar() {
    // no error
    unsafe {
        unsf();
        *PTR;
        VOID = ();
        &PACKED.data;
    }
}

unsafe fn baz() {
    unsafe { unsafe { unsf() } }
    //~^ ERROR unnecessary `unsafe` block
}

#[allow(unsafe_op_in_unsafe_fn)]
unsafe fn qux() {
    // lint allowed -> no error
    unsf();
    *PTR;
    VOID = ();
    &PACKED.data;

    unsafe { unsf() }
    //~^ ERROR unnecessary `unsafe` block
}

fn main() {
    unsf()
    //~^ ERROR call to unsafe function is unsafe and requires unsafe function or block
}
<|endoftext|>


<commit_before>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

#![feature(plugin)]
#[plugin] #[no_link]
extern crate regex_macros;
extern crate regex;
// use regex::Regex;
use std::ascii::AsciiExt;
use std::collections;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::io;
use std::io::{BufferedReader, BufferedWriter, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref x) => {
            let file = try!(File::create(&Path::new(x.as_slice())));
            Box::new(BufferedWriter::new(file)) as Box<Writer>
        }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = collections::HashMap::<String, u32>::new();
    // let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = regex!(r"\w+");
    // let re = Regex::new(r"\w+").unwrap();
    // let re = regex!(r"[a-zA-Z0-9_]+");
    // let re = Regex::new(r"[a-zA-Z0-9_]+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    match map.entry(word) {
                        Occupied(mut view) => { *view.get_mut() += 1; }
                        Vacant(view) => { view.insert(1); }
                    }
                }
            }
        }
    }

    // Write counts
    let mut words: Vec<&String> = map.keys().collect();
    words.sort();
    for word in words.iter() {
        if let Some(count) = map.get(*word) {
            try!(writeln!(writer, "{}\t{}", count, word));
        }
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<commit_msg>Fix naming consistency<commit_after>// Uncomment the following line to disable unstable warnings:
// #![allow(unstable)]

#![feature(plugin)]
#[plugin] #[no_link]
extern crate regex_macros;
extern crate regex;
// use regex::Regex;
use std::ascii::AsciiExt;
use std::collections;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::io;
use std::io::{BufferedReader, BufferedWriter, File, IoResult};

pub mod config;
pub mod btree_map;

fn do_work(cfg: &config::Config) -> IoResult<()> {
    // Open input and output files
    let mut readers = vec![];
    if cfg.input.is_empty() {
        readers.push(BufferedReader::new(Box::new(io::stdin()) as Box<Reader>));
    } else {
        for name in cfg.input.iter() {
            let file = try!(File::open(&Path::new(name.as_slice())));
            readers.push(BufferedReader::new(Box::new(file) as Box<Reader>));
        }
    }
    let mut writer = match cfg.output {
        Some(ref name) => {
            let file = try!(File::create(&Path::new(name.as_slice())));
            Box::new(BufferedWriter::new(file)) as Box<Writer>
        }
        None => { Box::new(io::stdout()) as Box<Writer> }
    };

    // Parse words
    let mut map = collections::HashMap::<String, u32>::new();
    // let mut map = btree_map::BTreeMap::<String, u32>::new();
    let re = regex!(r"\w+");
    // let re = Regex::new(r"\w+").unwrap();
    // let re = regex!(r"[a-zA-Z0-9_]+");
    // let re = Regex::new(r"[a-zA-Z0-9_]+").unwrap();
    for reader in readers.iter_mut() {
        for line in reader.lines() {
            for caps in re.captures_iter(line.unwrap().as_slice()) {
                if let Some(cap) = caps.at(0) {
                    let word = match cfg.ignore_case {
                        true  => cap.to_ascii_lowercase(),
                        false => cap.to_string(),
                    };
                    match map.entry(word) {
                        Occupied(mut view) => { *view.get_mut() += 1; }
                        Vacant(view) => { view.insert(1); }
                    }
                }
            }
        }
    }

    // Write counts
    let mut words: Vec<&String> = map.keys().collect();
    words.sort();
    for word in words.iter() {
        if let Some(count) = map.get(*word) {
            try!(writeln!(writer, "{}\t{}", count, word));
        }
    }
    Ok(())
}

#[cfg(not(test))]
fn main() {
    let cfg = match config::get_config(std::os::args()) {
        Ok(c) => c,
        Err(usage) => {
            println!("{}", usage);
            return;
        }
    };
    do_work(&cfg).unwrap();
}

#[test]
fn test_do_work() {
    let bad_filename = "/..no-such-file..";
    let cfg = config::Config {
        input: vec![bad_filename.to_string()],
        output: None,
        ignore_case: false,
    };
    match do_work(&cfg) {
        // should fail for bad input file (couldn't open file ... path=/..no-such-file..; ...)
        Err(e) => assert!(format!("{}", e).as_slice().contains(bad_filename), format!("{}", e)),
        _ => panic!()
    }
}

<|endoftext|>


<commit_before>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate serde_json;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate task_hookrs;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;
extern crate libimagtodo;

use std::process::exit;
use std::process::{Command, Stdio};
use std::io::stdin;
use std::io::BufRead;

use task_hookrs::import::{import, import_task, import_tasks};

use libimagrt::runtime::Runtime;
use libimagtodo::task::IntoTask;
use libimagutil::trace::trace_error;

mod ui;

use ui::build_ui;
fn main() {

    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));

    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let scmd = rt.cli().subcommand_name();
    match scmd {
        Some("tw-hook") => {
            let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
            if subcmd.is_present("add") {
                let stdin = stdin();
                let mut stdin = stdin.lock();
                let mut line = String::new();
                match stdin.read_line(&mut line) {
                    Ok(_) => { }
                    Err(e) => {
                        error!("{}", e);
                        return;
                    }
                };
                if let Ok(ttask) = import_task(&line.as_str()) {
                    let uuid = *ttask.uuid();
                    println!("{}", match serde_json::ser::to_string(&ttask) {
                        Ok(val) => val,
                        Err(e) => {
                            error!("{}", e);
                            return;
                        }
                    });
                    match ttask.into_filelockentry(rt.store()) {
                        Ok(val) => {
                            println!("Task {} stored in imag", uuid);
                            val
                        },
                        Err(e) => {
                            trace_error(&e);
                            error!("{}", e);
                            return;
                        }
                    };
                }
                else {
                    error!("No usable input");
                    return;
                }
            }
            else if subcmd.is_present("delete") {
                // The used hook is "on-modify". This hook gives two json-objects
                // per usage und wants one (the second one) back.
                let mut counter = 0;
                let stdin = stdin();
                let mut stdin = stdin.lock();
                if let Ok(ttasks) = import_tasks(stdin) {
                    for ttask in ttasks {
                        if counter % 2 == 1 {
                            // Only every second task is needed, the first one is the
                            // task before the change, and the second one after
                            // the change. The (maybe modified) second one is
                            // expected by taskwarrior.
                            println!("{}", match serde_json::ser::to_string(&ttask) {
                                Ok(val) => val,
                                Err(e) => {
                                    error!("{}", e);
                                    return;
                                }
                            });
                            match ttask.status() {
                                &task_hookrs::status::TaskStatus::Deleted => {
                                    match libimagtodo::delete::delete(rt.store(), *ttask.uuid()) {
                                        Ok(_) => {
                                            println!("Deleted task {}", *ttask.uuid());
                                        }
                                        Err(e) => {
                                            trace_error(&e);
                                            error!("{}", e);
                                            return;
                                        }
                                    }
                                }
                                _ => {
                                }
                            } // end match ttask.status()
                        } // end if c % 2
                        counter += 1;
                    } // end for
                } // end if let
                else {
                    error!("No usable input");
                }
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                unreachable!();
            }
        },
        Some("exec") => {
            let subcmd = rt.cli().subcommand_matches("exec").unwrap();
            let mut args = Vec::new();
            if let Some(exec_string) = subcmd.values_of("command") {
                for e in exec_string {
                    args.push(e);
                }
                let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| {
                    panic!("failed to execute taskwarrior: {}", e);
                });

                let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                    panic!("failed to unwrap output: {}", e);
                });
                let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                    panic!("failed to ececute: {}", e);
                });
                println!("{}", outstring);
            } else {
                panic!("faild to execute: You need to exec --command");
            }
        }
        Some("list") => {
            let subcmd = rt.cli().subcommand_matches("list").unwrap();
            let mut args = Vec::new();
            let verbose = subcmd.is_present("verbose");
            let iter = match libimagtodo::read::get_todo_iterator(rt.store()) {
                //let iter = match rt.store().retrieve_for_module("todo/taskwarrior") {
                Err(e) => {
                    error!("{}", e);
                    return;
                }
                Ok(val) => val,
            };
            for task in iter {
                match task {
                    Ok(val) => {
                        //let val = libimagtodo::task::Task::new(fle);
                        //println!("{:#?}", val.flentry);
                        let uuid = match val.flentry.get_header().read("todo.uuid") {
                            Ok(Some(u)) => u,
                            Ok(None) => continue,
                            Err(e) => {
                                error!("{}", e);
                                continue;
                            }
                        };
                        if verbose {
                            args.clear();
                            args.push(format!("uuid:{}", uuid));
                            args.push(format!("{}", "information"));
                            let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn()
                                .unwrap_or_else(|e| {
                                    error!("{}", e);
                                    panic!("failed");
                                });
                            let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                                panic!("failed to unwrap output: {}", e);
                            });
                            let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                                panic!("failed to ececute: {}", e);
                            });
                            println!("{}", outstring);
                        }
                        else {
                            println!("{}", match uuid {
                                toml::Value::String(s) => s,
                                _ => {
                                    error!("Unexpected type for todo.uuid: {}", uuid);
                                    continue;
                                },
                            });
                        }
                    }
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                } // end match task
            } // end for
        }
        _ => unimplemented!(),
    } // end match scmd
} // end main

<commit_msg>reduce warnings<commit_after>extern crate clap;
extern crate glob;
#[macro_use] extern crate log;
extern crate serde_json;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

extern crate task_hookrs;

extern crate libimagrt;
extern crate libimagstore;
extern crate libimagutil;
extern crate libimagtodo;

use std::process::exit;
use std::process::{Command, Stdio};
use std::io::stdin;
use std::io::BufRead;

use task_hookrs::import::{import_task, import_tasks};

use libimagrt::runtime::Runtime;
use libimagtodo::task::IntoTask;
use libimagutil::trace::trace_error;

mod ui;

use ui::build_ui;
fn main() {

    let name = "imag-todo";
    let version = &version!()[..];
    let about = "Interface with taskwarrior";
    let ui = build_ui(Runtime::get_default_cli_builder(name, version, about));

    let rt = {
        let rt = Runtime::new(ui);
        if rt.is_ok() {
            rt.unwrap()
        } else {
            println!("Could not set up Runtime");
            println!("{:?}", rt.unwrap_err());
            exit(1);
        }
    };

    let scmd = rt.cli().subcommand_name();
    match scmd {
        Some("tw-hook") => {
            let subcmd = rt.cli().subcommand_matches("tw-hook").unwrap();
            if subcmd.is_present("add") {
                let stdin = stdin();
                let mut stdin = stdin.lock();
                let mut line = String::new();
                match stdin.read_line(&mut line) {
                    Ok(_) => { }
                    Err(e) => {
                        error!("{}", e);
                        return;
                    }
                };
                if let Ok(ttask) = import_task(&line.as_str()) {
                    let uuid = *ttask.uuid();
                    println!("{}", match serde_json::ser::to_string(&ttask) {
                        Ok(val) => val,
                        Err(e) => {
                            error!("{}", e);
                            return;
                        }
                    });
                    match ttask.into_filelockentry(rt.store()) {
                        Ok(val) => {
                            println!("Task {} stored in imag", uuid);
                            val
                        },
                        Err(e) => {
                            trace_error(&e);
                            error!("{}", e);
                            return;
                        }
                    };
                }
                else {
                    error!("No usable input");
                    return;
                }
            }
            else if subcmd.is_present("delete") {
                // The used hook is "on-modify". This hook gives two json-objects
                // per usage und wants one (the second one) back.
                let mut counter = 0;
                let stdin = stdin();
                let stdin = stdin.lock();
                if let Ok(ttasks) = import_tasks(stdin) {
                    for ttask in ttasks {
                        if counter % 2 == 1 {
                            // Only every second task is needed, the first one is the
                            // task before the change, and the second one after
                            // the change. The (maybe modified) second one is
                            // expected by taskwarrior.
                            println!("{}", match serde_json::ser::to_string(&ttask) {
                                Ok(val) => val,
                                Err(e) => {
                                    error!("{}", e);
                                    return;
                                }
                            });
                            match ttask.status() {
                                &task_hookrs::status::TaskStatus::Deleted => {
                                    match libimagtodo::delete::delete(rt.store(), *ttask.uuid()) {
                                        Ok(_) => {
                                            println!("Deleted task {}", *ttask.uuid());
                                        }
                                        Err(e) => {
                                            trace_error(&e);
                                            error!("{}", e);
                                            return;
                                        }
                                    }
                                }
                                _ => {
                                }
                            } // end match ttask.status()
                        } // end if c % 2
                        counter += 1;
                    } // end for
                } // end if let
                else {
                    error!("No usable input");
                }
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                unreachable!();
            }
        },
        Some("exec") => {
            let subcmd = rt.cli().subcommand_matches("exec").unwrap();
            let mut args = Vec::new();
            if let Some(exec_string) = subcmd.values_of("command") {
                for e in exec_string {
                    args.push(e);
                }
                let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn().unwrap_or_else(|e| {
                    panic!("failed to execute taskwarrior: {}", e);
                });

                let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                    panic!("failed to unwrap output: {}", e);
                });
                let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                    panic!("failed to ececute: {}", e);
                });
                println!("{}", outstring);
            } else {
                panic!("faild to execute: You need to exec --command");
            }
        }
        Some("list") => {
            let subcmd = rt.cli().subcommand_matches("list").unwrap();
            let mut args = Vec::new();
            let verbose = subcmd.is_present("verbose");
            let iter = match libimagtodo::read::get_todo_iterator(rt.store()) {
                //let iter = match rt.store().retrieve_for_module("todo/taskwarrior") {
                Err(e) => {
                    error!("{}", e);
                    return;
                }
                Ok(val) => val,
            };
            for task in iter {
                match task {
                    Ok(val) => {
                        //let val = libimagtodo::task::Task::new(fle);
                        //println!("{:#?}", val.flentry);
                        let uuid = match val.flentry.get_header().read("todo.uuid") {
                            Ok(Some(u)) => u,
                            Ok(None) => continue,
                            Err(e) => {
                                error!("{}", e);
                                continue;
                            }
                        };
                        if verbose {
                            args.clear();
                            args.push(format!("uuid:{}", uuid));
                            args.push(format!("{}", "information"));
                            let tw_process = Command::new("task").stdin(Stdio::null()).args(&args).spawn()
                                .unwrap_or_else(|e| {
                                    error!("{}", e);
                                    panic!("failed");
                                });
                            let output = tw_process.wait_with_output().unwrap_or_else(|e| {
                                panic!("failed to unwrap output: {}", e);
                            });
                            let outstring = String::from_utf8(output.stdout).unwrap_or_else(|e| {
                                panic!("failed to ececute: {}", e);
                            });
                            println!("{}", outstring);
                        }
                        else {
                            println!("{}", match uuid {
                                toml::Value::String(s) => s,
                                _ => {
                                    error!("Unexpected type for todo.uuid: {}", uuid);
                                    continue;
                                },
                            });
                        }
                    }
                    Err(e) => {
                        error!("{}", e);
                        continue;
                    }
                } // end match task
            } // end for
        }
        _ => unimplemented!(),
    } // end match scmd
} // end main

<|endoftext|>


<commit_before>use core::mem::PinMut;
use core::marker::Unpin;

use futures_core::{Poll, Stream};
use futures_core::task;

/// A stream which is just a shim over an underlying instance of `Iterator`.
///
/// This stream will never block and is always ready.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Iter<I> {
    iter: I,
}

impl<I> Unpin for Iter<I> {}

/// Converts an `Iterator` into a `Stream` which is always ready
/// to yield the next value.
///
/// Iterators in Rust don't express the ability to block, so this adapter
/// simply always calls `iter.next()` and returns that.
///
/// ```rust
/// # extern crate futures;
/// # extern crate futures_executor;
/// use futures::prelude::*;
/// use futures::stream;
/// use futures_executor::block_on;
///
/// # fn main() {
/// let mut stream = stream::iter_ok::<_, ()>(vec![17, 19]);
/// assert_eq!(Ok(vec![17, 19]), block_on(stream.collect()));
/// # }
/// ```
pub fn iter<I>(i: I) -> Iter<I::IntoIter>
    where I: IntoIterator,
{
    Iter {
        iter: i.into_iter(),
    }
}

impl<I> Stream for Iter<I>
    where I: Iterator,
{
    type Item = I::Item;

    fn poll_next(mut self: PinMut<Self>, _: &mut task::Context) -> Poll<Option<I::Item>> {
        Poll::Ready(self.iter.next())
    }
}
<commit_msg>Fix bug in stream iter doc<commit_after>use core::mem::PinMut;
use core::marker::Unpin;

use futures_core::{Poll, Stream};
use futures_core::task;

/// A stream which is just a shim over an underlying instance of `Iterator`.
///
/// This stream will never block and is always ready.
#[derive(Debug)]
#[must_use = "streams do nothing unless polled"]
pub struct Iter<I> {
    iter: I,
}

impl<I> Unpin for Iter<I> {}

/// Converts an `Iterator` into a `Stream` which is always ready
/// to yield the next value.
///
/// Iterators in Rust don't express the ability to block, so this adapter
/// simply always calls `iter.next()` and returns that.
///
/// ```rust
/// # extern crate futures;
/// # extern crate futures_executor;
/// use futures::prelude::*;
/// use futures::stream;
/// use futures_executor::block_on;
///
/// # fn main() {
/// let mut stream = stream::iter(vec![17, 19]);
/// assert_eq!(Ok(vec![17, 19]), block_on(stream.collect()));
/// # }
/// ```
pub fn iter<I>(i: I) -> Iter<I::IntoIter>
    where I: IntoIterator,
{
    Iter {
        iter: i.into_iter(),
    }
}

impl<I> Stream for Iter<I>
    where I: Iterator,
{
    type Item = I::Item;

    fn poll_next(mut self: PinMut<Self>, _: &mut task::Context) -> Poll<Option<I::Item>> {
        Poll::Ready(self.iter.next())
    }
}
<|endoftext|>


<commit_before>//! Crate `ruma-api-macros` provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! See the documentation for the `ruma_api!` macro for usage details.

#![deny(missing_copy_implementations, missing_debug_implementations)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use std::convert::TryFrom as _;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);
    match Api::try_from(raw_api) {
        Ok(api) => api.into_token_stream().into(),
        Err(err) => err.to_compile_error().into(),
    }
}
<commit_msg>Update ruma-api-macro's crate docs<commit_after>//! Crate ruma-api-macros provides a procedural macro for easily generating
//! [ruma-api](https://github.com/ruma/ruma-api)-compatible endpoints.
//!
//! This crate should never be used directly; instead, use it through the
//! re-exports in ruma-api. Also note that for technical reasons, the
//! `ruma_api!` macro is only documented in ruma-api, not here.

#![deny(missing_copy_implementations, missing_debug_implementations)]
#![allow(clippy::cognitive_complexity)]
// Since we support Rust 1.36.0, we can't apply this suggestion yet
#![allow(clippy::use_self)]
#![recursion_limit = "256"]

extern crate proc_macro;

use std::convert::TryFrom as _;

use proc_macro::TokenStream;
use quote::ToTokens;

use crate::api::{Api, RawApi};

mod api;

#[proc_macro]
pub fn ruma_api(input: TokenStream) -> TokenStream {
    let raw_api = syn::parse_macro_input!(input as RawApi);
    match Api::try_from(raw_api) {
        Ok(api) => api.into_token_stream().into(),
        Err(err) => err.to_compile_error().into(),
    }
}
<|endoftext|>