<commit_before>//! Contains utilities for stdout and stderr.
use crate::io::AsyncWrite;
use std::pin::Pin;
use std::task::{Context, Poll};
/// # Windows
/// AsyncWrite adapter that finds last char boundary in given buffer and does not write the rest.
/// That's why, wrapped writer will always receive well-formed utf-8 bytes.
/// # Other platforms
/// passes data to `inner` as is
#[derive(Debug)]
pub(crate) struct SplitByUtf8BoundaryIfWindows<W> {
    inner: W,
}

impl<W> SplitByUtf8BoundaryIfWindows<W> {
    pub(crate) fn new(inner: W) -> Self {
        Self { inner }
    }
}

impl<W> crate::io::AsyncWrite for SplitByUtf8BoundaryIfWindows<W>
where
    W: AsyncWrite + Unpin,
{
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        // following two ifs are enabled only on windows targets, because
        // on other targets we do not have problems with incomplete utf8 chars

        // ensure buffer is not longer than MAX_BUF
        #[cfg(any(target_os = "windows", test))]
        let buf = if buf.len() > crate::io::blocking::MAX_BUF {
            &buf[..crate::io::blocking::MAX_BUF]
        } else {
            buf
        };
        // now remove possible trailing incomplete character
        #[cfg(any(target_os = "windows", test))]
        let buf = match std::str::from_utf8(buf) {
            // `buf` is already utf-8, no need to trim it futher
            Ok(_) => buf,
            Err(err) => {
                let bad_bytes = buf.len() - err.valid_up_to();
                // TODO: this is too conservative
                const MAX_BYTES_PER_CHAR: usize = 8;

                if bad_bytes <= MAX_BYTES_PER_CHAR && err.valid_up_to() > 0 {
                    // Input data is probably UTF-8, but last char was split
                    // after trimming.
                    // let's exclude this character from the buf
                    &buf[..err.valid_up_to()]
                } else {
                    // UTF-8 violation could not be caused by trimming.
                    // Let's pass buffer to underlying writer as is.
                    // Why do not we return error here? It is possible
                    // that stdout is not console. Such streams allow
                    // non-utf8 data. That's why, let's defer to underlying
                    // writer and let it return error if needed
                    buf
                }
            }
        };
        // now pass trimmed input buffer to inner writer
        Pin::new(&mut self.inner).poll_write(cx, buf)
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.inner).poll_flush(cx)
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.inner).poll_shutdown(cx)
    }
}

#[cfg(test)]
mod tests {
    use crate::io::AsyncWriteExt;
    use std::io;
    use std::pin::Pin;
    use std::task::Context;
    use std::task::Poll;

    const MAX_BUF: usize = 16 * 1024;
    struct MockWriter;
    impl crate::io::AsyncWrite for MockWriter {
        fn poll_write(
            self: Pin<&mut Self>,
            _cx: &mut Context<'_>,
            buf: &[u8],
        ) -> Poll<Result<usize, io::Error>> {
            assert!(buf.len() <= MAX_BUF);
            assert!(std::str::from_utf8(buf).is_ok());
            Poll::Ready(Ok(buf.len()))
        }

        fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
            Poll::Ready(Ok(()))
        }

        fn poll_shutdown(
            self: Pin<&mut Self>,
            _cx: &mut Context<'_>,
        ) -> Poll<Result<(), io::Error>> {
            Poll::Ready(Ok(()))
        }
    }
    #[test]
    #[cfg(not(loom))]
    fn test_splitter() {
        let data = str::repeat("█", MAX_BUF);
        let mut wr = super::SplitByUtf8BoundaryIfWindows::new(MockWriter);
        let fut = async move {
            wr.write_all(data.as_bytes()).await.unwrap();
        };
        crate::runtime::Builder::new()
            .basic_scheduler()
            .build()
            .unwrap()
            .block_on(fut);
    }
}
<commit_msg>io: move #[cfg(not(loom))] to fix warning (#2864)<commit_after>//! Contains utilities for stdout and stderr.
use crate::io::AsyncWrite;
use std::pin::Pin;
use std::task::{Context, Poll};
/// # Windows
/// AsyncWrite adapter that finds last char boundary in given buffer and does not write the rest.
/// That's why, wrapped writer will always receive well-formed utf-8 bytes.
/// # Other platforms
/// passes data to `inner` as is
#[derive(Debug)]
pub(crate) struct SplitByUtf8BoundaryIfWindows<W> {
    inner: W,
}

impl<W> SplitByUtf8BoundaryIfWindows<W> {
    pub(crate) fn new(inner: W) -> Self {
        Self { inner }
    }
}

impl<W> crate::io::AsyncWrite for SplitByUtf8BoundaryIfWindows<W>
where
    W: AsyncWrite + Unpin,
{
    fn poll_write(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
        buf: &[u8],
    ) -> Poll<Result<usize, std::io::Error>> {
        // following two ifs are enabled only on windows targets, because
        // on other targets we do not have problems with incomplete utf8 chars

        // ensure buffer is not longer than MAX_BUF
        #[cfg(any(target_os = "windows", test))]
        let buf = if buf.len() > crate::io::blocking::MAX_BUF {
            &buf[..crate::io::blocking::MAX_BUF]
        } else {
            buf
        };
        // now remove possible trailing incomplete character
        #[cfg(any(target_os = "windows", test))]
        let buf = match std::str::from_utf8(buf) {
            // `buf` is already utf-8, no need to trim it futher
            Ok(_) => buf,
            Err(err) => {
                let bad_bytes = buf.len() - err.valid_up_to();
                // TODO: this is too conservative
                const MAX_BYTES_PER_CHAR: usize = 8;

                if bad_bytes <= MAX_BYTES_PER_CHAR && err.valid_up_to() > 0 {
                    // Input data is probably UTF-8, but last char was split
                    // after trimming.
                    // let's exclude this character from the buf
                    &buf[..err.valid_up_to()]
                } else {
                    // UTF-8 violation could not be caused by trimming.
                    // Let's pass buffer to underlying writer as is.
                    // Why do not we return error here? It is possible
                    // that stdout is not console. Such streams allow
                    // non-utf8 data. That's why, let's defer to underlying
                    // writer and let it return error if needed
                    buf
                }
            }
        };
        // now pass trimmed input buffer to inner writer
        Pin::new(&mut self.inner).poll_write(cx, buf)
    }

    fn poll_flush(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.inner).poll_flush(cx)
    }

    fn poll_shutdown(
        mut self: Pin<&mut Self>,
        cx: &mut Context<'_>,
    ) -> Poll<Result<(), std::io::Error>> {
        Pin::new(&mut self.inner).poll_shutdown(cx)
    }
}

#[cfg(test)]
#[cfg(not(loom))]
mod tests {
    use crate::io::AsyncWriteExt;
    use std::io;
    use std::pin::Pin;
    use std::task::Context;
    use std::task::Poll;

    const MAX_BUF: usize = 16 * 1024;
    struct MockWriter;
    impl crate::io::AsyncWrite for MockWriter {
        fn poll_write(
            self: Pin<&mut Self>,
            _cx: &mut Context<'_>,
            buf: &[u8],
        ) -> Poll<Result<usize, io::Error>> {
            assert!(buf.len() <= MAX_BUF);
            assert!(std::str::from_utf8(buf).is_ok());
            Poll::Ready(Ok(buf.len()))
        }

        fn poll_flush(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Result<(), io::Error>> {
            Poll::Ready(Ok(()))
        }

        fn poll_shutdown(
            self: Pin<&mut Self>,
            _cx: &mut Context<'_>,
        ) -> Poll<Result<(), io::Error>> {
            Poll::Ready(Ok(()))
        }
    }

    #[test]
    fn test_splitter() {
        let data = str::repeat("█", MAX_BUF);
        let mut wr = super::SplitByUtf8BoundaryIfWindows::new(MockWriter);
        let fut = async move {
            wr.write_all(data.as_bytes()).await.unwrap();
        };
        crate::runtime::Builder::new()
            .basic_scheduler()
            .build()
            .unwrap()
            .block_on(fut);
    }
}
<|endoftext|>


<commit_before>use std::string::String;
use ropey::Rope;
use std::fs::File;
use std::cmp;
use std::io::{Read, Write, Result, Error, ErrorKind};
use std::path::Path;
use super::{Movement, Editable, Named, Saveable, CharIter};

#[derive(Debug)]
pub struct Text {
    pub pos: usize,
    pub text: Rope,
    pub name: String,
}

impl Text {
    pub fn empty() -> Text {
        Text {
            pos: 0,
            text: Rope::from_str("\n"),
            name: String::new(),
        }
    }
    pub fn open_file(filename: String) -> Result<Text> {
        if Path::new(&filename).exists() {
            let mut file = File::open(&filename)?;

            let mut buf = String::new();
            file.read_to_string(&mut buf)?;
            if buf.is_empty() {
                buf = "\n".to_owned();
            }
            let text = Rope::from_string(buf);

            Ok(Text {
                   pos: 0,
                   text: text,
                   name: filename,
               })
        } else {
            let mut text = Text::empty();
            text.set_name(filename);
            Ok(text)
        }
    }
}

impl Saveable for Text {
    fn save(&self) -> Result<()> {
        if self.name.is_empty() {
            return Err(Error::new(ErrorKind::InvalidInput, "Can't write file with no name"));
        }
        let mut file = File::create(&self.name)?;
        for c in self.text.char_iter() {
            write!(file, "{}", c)?;
        }
        file.sync_all()?;
        Ok(())
    }
}

impl Named for Text {
    fn name(&self) -> &String {
        &self.name
    }
    fn set_name(&mut self, name: String) {
        self.name = name;
    }
}

impl Editable for Text {
    fn step(&mut self, mov: Movement) {
        match mov {
            Movement::Up => {
                if self.line() > 0 {
                    let prev_line = self.text.line_index_to_char_index(self.line() - 1);
                    let prev_line_size = self.text
                        .line_iter()
                        .nth(self.line() - 1)
                        .unwrap()
                        .char_count();
                    self.pos = prev_line + cmp::min(self.col(), prev_line_size - 1);
                }
            }
            Movement::Down => {
                if self.line() < self.line_count() - 1 {
                    let next_line = self.text.line_index_to_char_index(self.line() + 1);
                    let next_line_size = self.text
                        .line_iter()
                        .nth(self.line() + 1)
                        .unwrap()
                        .char_count();
                    self.pos = next_line + cmp::min(self.col(), next_line_size - 1);
                }
            }
            Movement::PageUp(up) => {
                let target_line = if self.line() < up {
                    0
                } else {
                    self.line() - up
                };
                self.pos = self.text.line_index_to_char_index(target_line);
            }
            Movement::PageDown(down) => {
                let target_line = if self.line_count() - self.line() < down {
                    self.line_count() - 1
                } else {
                    self.line() + down
                };
                self.pos = self.text.line_index_to_char_index(target_line);
            }
            Movement::Left => {
                if self.pos > 0 {
                    self.pos -= 1;
                }
            }
            Movement::Right => {
                if self.pos < self.text.char_count() - 1 {
                    self.pos += 1;
                }
            }
            Movement::LineStart => {
                let curr_line = self.text.line_index_to_char_index(self.line());

                self.pos = curr_line;
            }
            Movement::LineEnd => {
                let curr_line = self.text.line_index_to_char_index(self.line());
                let curr_line_size = self.text
                    .line_iter()
                    .nth(self.line())
                    .unwrap()
                    .char_count();
                self.pos = curr_line + curr_line_size - 1;
            }
        }
    }

    fn insert(&mut self, c: char) {
        self.text.insert_text_at_char_index(&format!("{}", c), self.pos);
        self.pos += 1;
    }
    fn insert_forward(&mut self, c: char) {
        self.text.insert_text_at_char_index(&format!("{}", c), self.pos);
    }

    fn delete(&mut self) -> Option<char> {
        if self.pos == 0 {
            None
        } else {
            self.pos -= 1;
            let ch = self.text.char_at_index(self.pos);
            self.text.remove_text_between_char_indices(self.pos, self.pos + 1);
            Some(ch)
        }
    }

    fn delete_forward(&mut self) -> Option<char> {
        if self.pos < self.len() - 1 {
            let ch = self.text.char_at_index(self.pos);
            self.text.remove_text_between_char_indices(self.pos, self.pos + 1);
            Some(ch)
        } else {
            None
        }
    }

    fn move_to(&mut self, pos: usize) {
        assert!(pos < self.text.char_count());
        self.pos = pos;
    }

    fn move_at(&mut self, line: usize, col: usize) {
        let line = cmp::min(line, self.line_count() - 1);
        let col = cmp::min(col,
                           self.text
                               .line_iter()
                               .nth(line)
                               .unwrap()
                               .char_count() - 1);
        self.pos = self.text.line_index_to_char_index(line) + col;
    }

    fn pos(&self) -> usize {
        self.pos
    }

    fn line(&self) -> usize {
        self.text.char_index_to_line_index(self.pos)
    }

    fn col(&self) -> usize {
        self.pos - self.text.line_index_to_char_index(self.line())
    }

    fn line_count(&self) -> usize {
        self.text.line_ending_count()
    }

    fn len(&self) -> usize {
        self.text.char_count()
    }

    fn iter(&self) -> CharIter {
        self.text.char_iter()
    }

    fn iter_line(&self, line: usize) -> CharIter {
        self.text
            .line_iter_at_index(line)
            .next()
            .unwrap()
            .char_iter()
    }

    fn line_index_to_char_index(&self, line: usize) -> usize {
        self.text.line_index_to_char_index(line)
    }
}
<commit_msg>fix #7<commit_after>use std::string::String;
use ropey::Rope;
use std::fs::File;
use std::cmp;
use std::io::{Read, Write, Result, Error, ErrorKind};
use std::path::Path;
use super::{Movement, Editable, Named, Saveable, CharIter};

#[derive(Debug)]
pub struct Text {
    pub pos: usize,
    pub text: Rope,
    pub name: String,
}

impl Text {
    pub fn empty() -> Text {
        Text {
            pos: 0,
            text: Rope::from_str("\n"),
            name: String::new(),
        }
    }
    pub fn open_file(filename: String) -> Result<Text> {
        if Path::new(&filename).exists() {
            let mut file = File::open(&filename)?;

            let mut buf = String::new();
            file.read_to_string(&mut buf)?;

            match buf.chars().last() {
                Some('\n') => {}
                _ => buf.push('\n'),
            }
            let text = Rope::from_string(buf);

            Ok(Text {
                   pos: 0,
                   text: text,
                   name: filename,
               })
        } else {
            let mut text = Text::empty();
            text.set_name(filename);
            Ok(text)
        }
    }
}

impl Saveable for Text {
    fn save(&self) -> Result<()> {
        if self.name.is_empty() {
            return Err(Error::new(ErrorKind::InvalidInput, "Can't write file with no name"));
        }
        let mut file = File::create(&self.name)?;
        for c in self.text.char_iter() {
            write!(file, "{}", c)?;
        }
        file.sync_all()?;
        Ok(())
    }
}

impl Named for Text {
    fn name(&self) -> &String {
        &self.name
    }
    fn set_name(&mut self, name: String) {
        self.name = name;
    }
}

impl Editable for Text {
    fn step(&mut self, mov: Movement) {
        match mov {
            Movement::Up => {
                if self.line() > 0 {
                    let prev_line = self.text.line_index_to_char_index(self.line() - 1);
                    let prev_line_size = self.text
                        .line_iter()
                        .nth(self.line() - 1)
                        .unwrap()
                        .char_count();
                    self.pos = prev_line + cmp::min(self.col(), prev_line_size - 1);
                }
            }
            Movement::Down => {
                if self.line() < self.line_count() - 1 {
                    let next_line = self.text.line_index_to_char_index(self.line() + 1);
                    let next_line_size = self.text
                        .line_iter()
                        .nth(self.line() + 1)
                        .unwrap()
                        .char_count();
                    self.pos = next_line + cmp::min(self.col(), next_line_size - 1);
                }
            }
            Movement::PageUp(up) => {
                let target_line = if self.line() < up {
                    0
                } else {
                    self.line() - up
                };
                self.pos = self.text.line_index_to_char_index(target_line);
            }
            Movement::PageDown(down) => {
                let target_line = if self.line_count() - self.line() < down {
                    self.line_count() - 1
                } else {
                    self.line() + down
                };
                self.pos = self.text.line_index_to_char_index(target_line);
            }
            Movement::Left => {
                if self.pos > 0 {
                    self.pos -= 1;
                }
            }
            Movement::Right => {
                if self.pos < self.text.char_count() - 1 {
                    self.pos += 1;
                }
            }
            Movement::LineStart => {
                let curr_line = self.text.line_index_to_char_index(self.line());

                self.pos = curr_line;
            }
            Movement::LineEnd => {
                let curr_line = self.text.line_index_to_char_index(self.line());
                let curr_line_size = self.text
                    .line_iter()
                    .nth(self.line())
                    .unwrap()
                    .char_count();
                self.pos = curr_line + curr_line_size - 1;
            }
        }
    }

    fn insert(&mut self, c: char) {
        self.text.insert_text_at_char_index(&format!("{}", c), self.pos);
        self.pos += 1;
    }
    fn insert_forward(&mut self, c: char) {
        self.text.insert_text_at_char_index(&format!("{}", c), self.pos);
    }

    fn delete(&mut self) -> Option<char> {
        if self.pos == 0 {
            None
        } else {
            self.pos -= 1;
            let ch = self.text.char_at_index(self.pos);
            self.text.remove_text_between_char_indices(self.pos, self.pos + 1);
            Some(ch)
        }
    }

    fn delete_forward(&mut self) -> Option<char> {
        if self.pos < self.len() - 1 {
            let ch = self.text.char_at_index(self.pos);
            self.text.remove_text_between_char_indices(self.pos, self.pos + 1);
            Some(ch)
        } else {
            None
        }
    }

    fn move_to(&mut self, pos: usize) {
        assert!(pos < self.text.char_count());
        self.pos = pos;
    }

    fn move_at(&mut self, line: usize, col: usize) {
        let line = cmp::min(line, self.line_count() - 1);
        let col = cmp::min(col,
                           self.text
                               .line_iter()
                               .nth(line)
                               .unwrap()
                               .char_count() - 1);
        self.pos = self.text.line_index_to_char_index(line) + col;
    }

    fn pos(&self) -> usize {
        self.pos
    }

    fn line(&self) -> usize {
        self.text.char_index_to_line_index(self.pos)
    }

    fn col(&self) -> usize {
        self.pos - self.text.line_index_to_char_index(self.line())
    }

    fn line_count(&self) -> usize {
        self.text.line_ending_count()
    }

    fn len(&self) -> usize {
        self.text.char_count()
    }

    fn iter(&self) -> CharIter {
        self.text.char_iter()
    }

    fn iter_line(&self, line: usize) -> CharIter {
        self.text
            .line_iter_at_index(line)
            .next()
            .unwrap()
            .char_iter()
    }

    fn line_index_to_char_index(&self, line: usize) -> usize {
        self.text.line_index_to_char_index(line)
    }
}
<|endoftext|>


<commit_before>use std::fmt::{self, Display, Debug};
use std::error::Error;
use std::any::Any;
use std::cell::Cell;
use std::io::Read;
use std::io;
use std::ptr::copy;
use log::{log, trace};
use nom;

pub const DEFAULT_BUF_SIZE: usize = 256 * 1024;

pub trait StreamBuf<O> {
    fn fill(&mut self, min_count: usize) -> Result<(), FillError>;
    fn relocate(&mut self);
    fn consume(&mut self, count: usize);
    fn data(&self) -> &[O];
    fn needed(&self) -> Option<nom::Needed>;
    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [O], E>> where
        O: 'b, C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E>;

    fn fill_apply<'b, C, CO, E>(&'b mut self, combinator: C) -> Result<Option<CO>, FillApplyError<&'b [O], E>> where
        C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E> {

        match self.needed() {
            Some(nom::Needed::Size(bytes)) => self.fill(bytes)?,
            Some(nom::Needed::Unknown) => self.fill(1)?,
            None => ()
        }

        Ok(self.apply(combinator)?)
    }
}

#[derive(Debug)]
pub enum FillError {
    Io(io::Error),
    BufferOverflow(usize, usize),
}

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

impl Display for FillError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FillError::Io(ref e) => write!(f, "Failed to read data: {}", e),
            FillError::BufferOverflow(needed, capacity) => write!(f, "Cannot fill buffer of size {} bytes with {} bytes of data", capacity, needed),
        }
    }
}

impl Error for FillError {
    fn description(&self) -> &str {
        match *self {
            FillError::Io(_) => "I/O error",
            FillError::BufferOverflow(_, _) => "buffer overflow",
        }
    }
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FillError::Io(ref e) => Some(e),
            FillError::BufferOverflow(_, _) => None,
        }
    }
}

#[derive(Debug)]
pub enum FillApplyError<I, E> {
    Parser(nom::Err<I, E>),
    FillError(FillError),
}

impl<I, E> From<nom::Err<I, E>> for FillApplyError<I, E> {
    fn from(e: nom::Err<I, E>) -> FillApplyError<I, E> {
        FillApplyError::Parser(e)
    }
}

impl<I, E> From<FillError> for FillApplyError<I, E> {
    fn from(e: FillError) -> FillApplyError<I, E> {
        FillApplyError::FillError(e)
    }
}

impl<I, E> Display for FillApplyError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FillApplyError::Parser(ref e) => write!(f, "Failed to parse data: {}", e),
            FillApplyError::FillError(ref e) => write!(f, "Failed to fill buffer with amout of data requested by parser: {}", e),
        }
    }
}

impl<I, E> Error for FillApplyError<I, E> where I: Debug + Display + Any, E: Error {
    fn description(&self) -> &str {
        match *self {
            FillApplyError::Parser(_) => "parsing faield",
            FillApplyError::FillError(_) => "buffer fill error",
        }
    }
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FillApplyError::Parser(_) => None, // e contains reference to data
            FillApplyError::FillError(ref e) => Some(e),
        }
    }
}

pub struct ReadStreamBuf<R: Read> {
    reader: R,
    buf: Vec<u8>,
    needed: Cell<Option<nom::Needed>>,
    offset: Cell<usize>,
    prefetch: bool,
}

impl<R: Read> ReadStreamBuf<R> {
    pub fn new(reader: R) -> ReadStreamBuf<R> {
        ReadStreamBuf::with_capacity(reader, DEFAULT_BUF_SIZE)
    }

    pub fn with_capacity(reader: R, cap: usize) -> ReadStreamBuf<R> {
        ReadStreamBuf {
            reader: reader,
            buf: Vec::with_capacity(cap),
            needed: Cell::new(Some(nom::Needed::Unknown)),
            offset: Cell::new(0),
            prefetch: true,
        }
    }

    pub fn disable_prefetch(&mut self) {
        self.prefetch = false
    }

    pub fn into_inner(self) -> R {
        self.reader
    }
}

impl<R: Read> StreamBuf<u8> for ReadStreamBuf<R> {
    fn fill(&mut self, min_bytes: usize) -> Result<(), FillError> {
        let len = self.buf.len();
        let have = len - self.offset.get();

        if have >= min_bytes {
            return Ok(())
        }

        let needed = min_bytes - have;
        let cap = self.buf.capacity();

        if min_bytes > cap {
            return Err(FillError::BufferOverflow(min_bytes, cap))
        }

        if len + needed > cap {
            self.relocate();
            debug_assert_eq!(self.offset.get(), 0);
            debug_assert_eq!(self.buf.len(), have);
            debug_assert_eq!(self.buf.capacity(), cap);
            return self.fill(min_bytes)
        }

        // using set_len instead of resize as we will initialize the extra space in the vec with
        // read; this yields 100% improvement in stream_buf bench
        // this depends on the buf to be of size cap; also note unsafe in relocate
        trace!("reading exactly {} bytes into buf blocking: {}..{} ({}); have: {} will have: {}", needed, len, len + needed, self.buf[len..len + needed].len(), have, have + needed);

        unsafe { self.buf.set_len(len + needed) };
        if let Err(err) = self.reader.read_exact(&mut self.buf[len..len + needed]) {
            unsafe { self.buf.set_len(len) };
            return Err(From::from(err));
        }

        // Try to read to the end of the buffer if we can
        if self.prefetch && len + needed < cap {
            trace!("reading up to {} extra bytes into buf non blocking", cap - (len + needed));
            unsafe { self.buf.set_len(cap) };
            match self.reader.read(&mut self.buf[len + needed..cap]) {
                Err(err) => {
                    unsafe { self.buf.set_len(len + needed) };
                    return Err(From::from(err));
                },
                Ok(bytes_read) => {
                    trace!("got extra {} bytes", bytes_read);
                    unsafe { self.buf.set_len(len + needed + bytes_read) };
                }
            }
        }

        //trace!("buf has: {:?}", self.data());
        trace!("buf has {} bytes", self.data().len());
        debug_assert!(self.buf.len() - self.offset.get() >= min_bytes);
        Ok(())
    }

    fn relocate(&mut self) {
        let offset = self.offset.get();
        if offset == 0 {
            return
        }

        let len = self.buf.len();
        let have = len - offset;

        // This does same thing as:
        // self.buf = self.buf.split_off(self.offset.get());
        // but avoids alloation by moving the memory instead of slicing + freeing + allocating
        unsafe {
            copy(self.buf[offset..len].as_ptr(), self.buf.as_mut_ptr(), have);
        }

        self.buf.truncate(have);
        self.offset.set(0);
    }

    fn consume(&mut self, bytes: usize) {
        let len = self.buf.len();

        let consume = if self.offset.get() + bytes > len {
            len - self.offset.get()
        } else {
            bytes
        };
        self.offset.set(self.offset.get() + consume);
    }

    fn data(&self) -> &[u8] {
        &self.buf[self.offset.get()..self.buf.len()]
    }

    fn needed(&self) -> Option<nom::Needed> {
        self.needed.get()
    }

    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [u8], E>> where
        C: Fn(&'b [u8]) -> nom::IResult<&'b [u8], CO, E> {
        let data = self.data();
        match combinator(data) {
            nom::IResult::Done(left, out) => {
                let consumed = data.len() - left.len();
                trace!("done: consumed: {}", consumed);

                // Move the offset
                self.offset.set(self.offset.get() + consumed);
                // We don't know how much we will need now
                self.needed.set(None);
                Ok(Some(out))
            },
            nom::IResult::Error(err) => Err(err),
            nom::IResult::Incomplete(needed) => {
                trace!("incomplete: needed: {:?}", needed);
                self.needed.set(Some(needed));
                Ok(None)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::StreamBuf;
    use super::ReadStreamBuf;
    use super::FillError;
    use nom::{IResult, Needed};
    use std::io::Cursor;

    fn subject(data: Vec<u8>) -> ReadStreamBuf<Cursor<Vec<u8>>> {
        ReadStreamBuf::new(Cursor::new(data))
    }

    fn subject_with_default_data() -> ReadStreamBuf<Cursor<Vec<u8>>> {
        subject(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    }

    #[test]
    fn reading() {
        let mut rsb = subject_with_default_data();
        assert!(rsb.data().is_empty());

        // fill reads as much as it can non-blocking
        // TODO: how to test blocking streaming?
        rsb.fill(3).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9].as_ref());
    }

    #[test]
    fn relocate() {
        let mut rsb = subject_with_default_data();

        //TODO: this test does nothing...
        rsb.fill(10).unwrap();
        rsb.relocate();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn consume() {
        let mut rsb = subject_with_default_data();

        rsb.fill(10).unwrap();
        rsb.consume(8);
        assert_eq!(rsb.data(), [8, 9].as_ref());
    }

    #[test]
    fn consume_more_than_we_have() {
        let mut rsb = subject_with_default_data();

        rsb.consume(3);
        rsb.fill(10).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn apply_function() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
    }

    #[test]
    fn apply_should_consume() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(1));
    }

    #[test]
    fn apply_converted_macro() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(closure!(tag!([0, 1]))).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_closure() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(|i| tag!(i, [0, 1])).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_custom_fuction_with_refs() {
        let mut rsb = subject_with_default_data();
        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        rsb.fill(3).unwrap();
        assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
    }

    #[test]
    fn needed_with_apply() {
        let mut rsb = subject_with_default_data();

        fn comb<'a>(input: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> {
            tag!(input, [0, 1, 2])
        }

        assert!(rsb.apply(comb).unwrap().is_none());

        let needed = rsb.needed().unwrap();
        assert_eq!(needed, Needed::Size(3));

        if let Needed::Size(bytes) = needed {
            rsb.fill(bytes).unwrap();
            assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        }
    }

    #[test]
    fn fill_apply() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        //TODO: test None scenario
        rsb.fill(10).unwrap();
        assert_eq!(rsb.fill_apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        assert_eq!(rsb.fill_apply(be_u8).unwrap(), Some(3));
    }

    #[test]
    fn fill_over_buf() {
        let mut rsb = subject_with_default_data();
        let error = rsb.fill(super::DEFAULT_BUF_SIZE + 1).unwrap_err();
        if let FillError::BufferOverflow(needed, capacity) = error {
            assert_eq!(needed, super::DEFAULT_BUF_SIZE + 1);
            assert_eq!(capacity, super::DEFAULT_BUF_SIZE);
        } else {
            panic!("was expecing BufferOverflow error");
        }
    }
}
<commit_msg>fixed panic on trace logging<commit_after>use std::fmt::{self, Display, Debug};
use std::error::Error;
use std::any::Any;
use std::cell::Cell;
use std::io::Read;
use std::io;
use std::ptr::copy;
use log::{log, trace};
use nom;

pub const DEFAULT_BUF_SIZE: usize = 256 * 1024;

pub trait StreamBuf<O> {
    fn fill(&mut self, min_count: usize) -> Result<(), FillError>;
    fn relocate(&mut self);
    fn consume(&mut self, count: usize);
    fn data(&self) -> &[O];
    fn needed(&self) -> Option<nom::Needed>;
    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [O], E>> where
        O: 'b, C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E>;

    fn fill_apply<'b, C, CO, E>(&'b mut self, combinator: C) -> Result<Option<CO>, FillApplyError<&'b [O], E>> where
        C: Fn(&'b [O]) -> nom::IResult<&'b [O], CO, E> {

        match self.needed() {
            Some(nom::Needed::Size(bytes)) => self.fill(bytes)?,
            Some(nom::Needed::Unknown) => self.fill(1)?,
            None => ()
        }

        Ok(self.apply(combinator)?)
    }
}

#[derive(Debug)]
pub enum FillError {
    Io(io::Error),
    BufferOverflow(usize, usize),
}

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

impl Display for FillError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FillError::Io(ref e) => write!(f, "Failed to read data: {}", e),
            FillError::BufferOverflow(needed, capacity) => write!(f, "Cannot fill buffer of size {} bytes with {} bytes of data", capacity, needed),
        }
    }
}

impl Error for FillError {
    fn description(&self) -> &str {
        match *self {
            FillError::Io(_) => "I/O error",
            FillError::BufferOverflow(_, _) => "buffer overflow",
        }
    }
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FillError::Io(ref e) => Some(e),
            FillError::BufferOverflow(_, _) => None,
        }
    }
}

#[derive(Debug)]
pub enum FillApplyError<I, E> {
    Parser(nom::Err<I, E>),
    FillError(FillError),
}

impl<I, E> From<nom::Err<I, E>> for FillApplyError<I, E> {
    fn from(e: nom::Err<I, E>) -> FillApplyError<I, E> {
        FillApplyError::Parser(e)
    }
}

impl<I, E> From<FillError> for FillApplyError<I, E> {
    fn from(e: FillError) -> FillApplyError<I, E> {
        FillApplyError::FillError(e)
    }
}

impl<I, E> Display for FillApplyError<I, E> where I: Debug, E: Debug {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        match *self {
            FillApplyError::Parser(ref e) => write!(f, "Failed to parse data: {}", e),
            FillApplyError::FillError(ref e) => write!(f, "Failed to fill buffer with amout of data requested by parser: {}", e),
        }
    }
}

impl<I, E> Error for FillApplyError<I, E> where I: Debug + Display + Any, E: Error {
    fn description(&self) -> &str {
        match *self {
            FillApplyError::Parser(_) => "parsing faield",
            FillApplyError::FillError(_) => "buffer fill error",
        }
    }
    fn cause(&self) -> Option<&dyn Error> {
        match *self {
            FillApplyError::Parser(_) => None, // e contains reference to data
            FillApplyError::FillError(ref e) => Some(e),
        }
    }
}

pub struct ReadStreamBuf<R: Read> {
    reader: R,
    buf: Vec<u8>,
    needed: Cell<Option<nom::Needed>>,
    offset: Cell<usize>,
    prefetch: bool,
}

impl<R: Read> ReadStreamBuf<R> {
    pub fn new(reader: R) -> ReadStreamBuf<R> {
        ReadStreamBuf::with_capacity(reader, DEFAULT_BUF_SIZE)
    }

    pub fn with_capacity(reader: R, cap: usize) -> ReadStreamBuf<R> {
        ReadStreamBuf {
            reader: reader,
            buf: Vec::with_capacity(cap),
            needed: Cell::new(Some(nom::Needed::Unknown)),
            offset: Cell::new(0),
            prefetch: true,
        }
    }

    pub fn disable_prefetch(&mut self) {
        self.prefetch = false
    }

    pub fn into_inner(self) -> R {
        self.reader
    }
}

impl<R: Read> StreamBuf<u8> for ReadStreamBuf<R> {
    fn fill(&mut self, min_bytes: usize) -> Result<(), FillError> {
        let len = self.buf.len();
        let have = len - self.offset.get();

        if have >= min_bytes {
            return Ok(())
        }

        let needed = min_bytes - have;
        let cap = self.buf.capacity();

        if min_bytes > cap {
            return Err(FillError::BufferOverflow(min_bytes, cap))
        }

        if len + needed > cap {
            self.relocate();
            debug_assert_eq!(self.offset.get(), 0);
            debug_assert_eq!(self.buf.len(), have);
            debug_assert_eq!(self.buf.capacity(), cap);
            return self.fill(min_bytes)
        }

        // using set_len instead of resize as we will initialize the extra space in the vec with
        // read; this yields 100% improvement in stream_buf bench
        // this depends on the buf to be of size cap; also note unsafe in relocate
        trace!("reading exactly {} bytes into buf blocking: {}..{}; have: {} will have: {}", needed, len, len + needed, have, have + needed);

        unsafe { self.buf.set_len(len + needed) };
        if let Err(err) = self.reader.read_exact(&mut self.buf[len..len + needed]) {
            unsafe { self.buf.set_len(len) };
            return Err(From::from(err));
        }

        // Try to read to the end of the buffer if we can
        if self.prefetch && len + needed < cap {
            trace!("reading up to {} extra bytes into buf non blocking", cap - (len + needed));
            unsafe { self.buf.set_len(cap) };
            match self.reader.read(&mut self.buf[len + needed..cap]) {
                Err(err) => {
                    unsafe { self.buf.set_len(len + needed) };
                    return Err(From::from(err));
                },
                Ok(bytes_read) => {
                    trace!("got extra {} bytes", bytes_read);
                    unsafe { self.buf.set_len(len + needed + bytes_read) };
                }
            }
        }

        //trace!("buf has: {:?}", self.data());
        trace!("buf has {} bytes", self.data().len());
        debug_assert!(self.buf.len() - self.offset.get() >= min_bytes);
        Ok(())
    }

    fn relocate(&mut self) {
        let offset = self.offset.get();
        if offset == 0 {
            return
        }

        let len = self.buf.len();
        let have = len - offset;

        // This does same thing as:
        // self.buf = self.buf.split_off(self.offset.get());
        // but avoids alloation by moving the memory instead of slicing + freeing + allocating
        unsafe {
            copy(self.buf[offset..len].as_ptr(), self.buf.as_mut_ptr(), have);
        }

        self.buf.truncate(have);
        self.offset.set(0);
    }

    fn consume(&mut self, bytes: usize) {
        let len = self.buf.len();

        let consume = if self.offset.get() + bytes > len {
            len - self.offset.get()
        } else {
            bytes
        };
        self.offset.set(self.offset.get() + consume);
    }

    fn data(&self) -> &[u8] {
        &self.buf[self.offset.get()..self.buf.len()]
    }

    fn needed(&self) -> Option<nom::Needed> {
        self.needed.get()
    }

    fn apply<'b, C, CO, E>(&'b self, combinator: C) -> Result<Option<CO>, nom::Err<&'b [u8], E>> where
        C: Fn(&'b [u8]) -> nom::IResult<&'b [u8], CO, E> {
        let data = self.data();
        match combinator(data) {
            nom::IResult::Done(left, out) => {
                let consumed = data.len() - left.len();
                trace!("done: consumed: {}", consumed);

                // Move the offset
                self.offset.set(self.offset.get() + consumed);
                // We don't know how much we will need now
                self.needed.set(None);
                Ok(Some(out))
            },
            nom::IResult::Error(err) => Err(err),
            nom::IResult::Incomplete(needed) => {
                trace!("incomplete: needed: {:?}", needed);
                self.needed.set(Some(needed));
                Ok(None)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::StreamBuf;
    use super::ReadStreamBuf;
    use super::FillError;
    use nom::{IResult, Needed};
    use std::io::Cursor;

    fn subject(data: Vec<u8>) -> ReadStreamBuf<Cursor<Vec<u8>>> {
        ReadStreamBuf::new(Cursor::new(data))
    }

    fn subject_with_default_data() -> ReadStreamBuf<Cursor<Vec<u8>>> {
        subject(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
    }

    #[test]
    fn reading() {
        let mut rsb = subject_with_default_data();
        assert!(rsb.data().is_empty());

        // fill reads as much as it can non-blocking
        // TODO: how to test blocking streaming?
        rsb.fill(3).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8 ,9].as_ref());
    }

    #[test]
    fn relocate() {
        let mut rsb = subject_with_default_data();

        //TODO: this test does nothing...
        rsb.fill(10).unwrap();
        rsb.relocate();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn consume() {
        let mut rsb = subject_with_default_data();

        rsb.fill(10).unwrap();
        rsb.consume(8);
        assert_eq!(rsb.data(), [8, 9].as_ref());
    }

    #[test]
    fn consume_more_than_we_have() {
        let mut rsb = subject_with_default_data();

        rsb.consume(3);
        rsb.fill(10).unwrap();
        assert_eq!(rsb.data(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9].as_ref());
    }

    #[test]
    fn apply_function() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
    }

    #[test]
    fn apply_should_consume() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(0));
        rsb.fill(1).unwrap();
        assert_eq!(rsb.apply(be_u8).unwrap(), Some(1));
    }

    #[test]
    fn apply_converted_macro() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(closure!(tag!([0, 1]))).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_closure() {
        let mut rsb = subject_with_default_data();

        rsb.fill(2).unwrap();
        assert_eq!(rsb.apply(|i| tag!(i, [0, 1])).unwrap(), Some([0, 1].as_ref()));
    }

    #[test]
    fn apply_custom_fuction_with_refs() {
        let mut rsb = subject_with_default_data();
        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        rsb.fill(3).unwrap();
        assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
    }

    #[test]
    fn needed_with_apply() {
        let mut rsb = subject_with_default_data();

        fn comb<'a>(input: &'a[u8]) -> IResult<&'a[u8], &'a[u8]> {
            tag!(input, [0, 1, 2])
        }

        assert!(rsb.apply(comb).unwrap().is_none());

        let needed = rsb.needed().unwrap();
        assert_eq!(needed, Needed::Size(3));

        if let Needed::Size(bytes) = needed {
            rsb.fill(bytes).unwrap();
            assert_eq!(rsb.apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        }
    }

    #[test]
    fn fill_apply() {
        use nom::be_u8;
        let mut rsb = subject_with_default_data();

        fn comb(input: &[u8]) -> IResult<&[u8], &[u8]> {
            tag!(input, [0, 1, 2])
        }

        //TODO: test None scenario
        rsb.fill(10).unwrap();
        assert_eq!(rsb.fill_apply(comb).unwrap(), Some([0, 1, 2].as_ref()));
        assert_eq!(rsb.fill_apply(be_u8).unwrap(), Some(3));
    }

    #[test]
    fn fill_over_buf() {
        let mut rsb = subject_with_default_data();
        let error = rsb.fill(super::DEFAULT_BUF_SIZE + 1).unwrap_err();
        if let FillError::BufferOverflow(needed, capacity) = error {
            assert_eq!(needed, super::DEFAULT_BUF_SIZE + 1);
            assert_eq!(capacity, super::DEFAULT_BUF_SIZE);
        } else {
            panic!("was expecing BufferOverflow error");
        }
    }
}
<|endoftext|>


<commit_before>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

#[macro_use]
use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Box<Self::List>) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (self:&Self, &mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res ;

    // Derived from above:
    fn is_empty (self:&Self, st:&mut A, list:&Self::List) -> bool {
        self.elim(st, &list, |_|true, |_,_,_|false, |_,_,_|false)
    }
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold_up<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Leaf) -> Res
        ,      BinC:Fn(&mut A, Bin, Res, Res ) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                  -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Box<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Box<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)               -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)      -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (self:&Self, st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, tl),
            List::Name(ref nm, ref tl) => namef(st, nm, tl),
            List::Rc(ref rc) => self.elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                self.elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager, prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (l, list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, l, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (l, list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    l.elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, l, &rest, &tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations, named by name.
                // TODO: Memoize the recursive calls to tree_of_list_rec.
                let tree = T::name( st, nm.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec::<A,X,T,L> ( st, l, &rest, &tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (l:&L, st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, l, list, &nil, 0 as u32, u32::max_value()) ;
    assert!( l.is_empty( st, &rest ) );
    tree
}
<commit_msg>minor<commit_after>use std::fmt::Debug;
use std::hash::Hash;
use std::rc::Rc;
use std::mem::replace;

#[macro_use]
use adapton_syntax::* ;
use adapton_sigs::* ;

pub trait ListT<A:Adapton,Hd> : Debug+Hash+PartialEq+Eq+Clone {
    type List : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::List ;
    fn cons (&mut A, Hd, Box<Self::List>) -> Self::List ;
    fn rc   (&mut A, Rc<Self::List>) -> Self::List ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::List>) -> Self::List ;
    fn art  (&mut A, Art<Self::List,A::Loc>) -> Self::List ;

    fn elim<Res,Nil,Cons,Name> (self:&Self, &mut A, &Self::List, Nil, Cons, Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res ;

    // Derived from above:
    fn is_empty (self:&Self, st:&mut A, list:&Self::List) -> bool {
        self.elim(st, &list, |_|true, |_,_,_|false, |_,_,_|false)
    }
}

// Questions:
//  - Should `Name`s always be passed by reference?
//  - Do these Fn argss for fold need to be passed in `Rc<Box<_>>`s ?

pub trait TreeT<A:Adapton,Leaf,Bin:Hash> : Debug+Hash+PartialEq+Eq+Clone {
    type Tree : Debug+Hash+PartialEq+Eq+Clone ;

    fn nil  (&mut A) -> Self::Tree ;
    fn leaf (&mut A, Leaf) -> Self::Tree ;
    fn bin  (&mut A, Bin, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;

    // requisite "adaptonic" constructors: `name` and `art`:
    fn name (&mut A, A::Name, Box<Self::Tree>, Box<Self::Tree>) -> Self::Tree ;
    fn art  (&mut A, Art<Self::Tree,A::Loc>) -> Self::Tree ;

    fn fold<Res,LeafC,BinC> (&mut A, Self::Tree, Res, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Res, Leaf) -> Res
        ,      BinC:Fn(&mut A, Res, Bin ) -> Res ;

    fn fold_up<Arg,Res,LeafC,BinC> (&mut A, Self::Tree, LeafC, BinC) -> Res
        where LeafC:Fn(&mut A, Leaf) -> Res
        ,      BinC:Fn(&mut A, Bin, Res, Res ) -> Res ;

    // TODO: Add derived operations (max, min, sum, etc.) for fold_up.
}

#[derive(Debug,PartialEq,Eq,Hash,Clone)]
enum List<A:Adapton,Hd> {
    Nil,
    Cons(Hd,      Box<List<A,Hd>>),
    Rc(           Rc<List<A,Hd>>),
    Name(A::Name, Box<List<A,Hd>>),
    Art(          Art<List<A,Hd>, A::Loc>),
}

// TODO: Why Does Adapton have to implement all of these?
//       It's not actually *contained* within the List structure; it cannot be ecountered there.
//       It's only ever present in a negative position (as a function parameter).
impl<A:Adapton+Debug+Hash+PartialEq+Eq+Clone,Hd:Debug+Hash+PartialEq+Eq+Clone> ListT<A,Hd> for List<A,Hd> {
    type List = List<A,Hd>;

    fn nil  (_:&mut A)                                  -> Self::List { List::Nil }
    fn cons (_:&mut A, hd:Hd, tl:Box<Self::List>)       -> Self::List { List::Cons(hd,tl) }
    fn name (_:&mut A, nm:A::Name, tl:Box<Self::List>)  -> Self::List { List::Name(nm, tl) }
    fn rc   (_:&mut A, rc:Rc<List<A,Hd>>)               -> Self::List { List::Rc(rc) }
    fn art  (_:&mut A, art:Art<List<A,Hd>,A::Loc>)      -> Self::List { List::Art(art) }

    fn elim<Res,Nil,Cons,Name> (self:&Self, st:&mut A, list:&Self::List, nilf:Nil, consf:Cons, namef:Name) -> Res
        where Nil:FnOnce(&mut A) -> Res
        ,    Cons:FnOnce(&mut A, &Hd, &Box<Self::List>) -> Res
        ,    Name:FnOnce(&mut A, &A::Name, &Box<Self::List>) -> Res
    {
        match *list {
            List::Nil => nilf(st),
            List::Cons(ref hd, ref tl) => consf(st, hd, tl),
            List::Name(ref nm, ref tl) => namef(st, nm, tl),
            List::Rc(ref rc) => self.elim(st, &*rc, nilf, consf, namef),
            List::Art(ref art) => {
                let list = st.force(art);
                self.elim(st, &list, nilf, consf, namef)
            }
        }
    }
}

fn tree_of_list_rec_memo <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32) ->
    (T::Tree, L::List)
{
    let t = st.thunk (ArtId::Eager, prog_pt!(tree_of_list_rec),
                      Rc::new(Box::new(|st, args|{
                          let (l, list, left_tree, left_tree_lev, parent_lev) = args ;
                          tree_of_list_rec::<A,X,T,L>
                              (st, l, list, left_tree, left_tree_lev, parent_lev)
                      })),
                      (l, list, left_tree, left_tree_lev, parent_lev)
                      ) ;
    st.force( &t )
}

fn tree_of_list_rec <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (st:&mut A, l:&L, list:&L::List, left_tree:&T::Tree, left_tree_lev:u32, parent_lev:u32)
     -> (T::Tree, L::List)
{
    l.elim (
        st, &list,
        /* Nil */  |st| ( T::nil(st), L::nil(st) ),
        /* Cons */ |st, hd, rest| {
            let lev_hd = (1 + (my_hash(hd).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_hd && lev_hd <= parent_lev {
                let nil = T::nil(st) ;
                let (right_tree, rest) = tree_of_list_rec::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_hd ) ;
                let tree = T::bin ( st, hd.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec::<A,X,T,L> ( st, l, &rest, &tree, lev_hd, parent_lev )
            }
            else {
                let rest = L::cons(st, hd.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }},
        /* Name */ |st, nm, rest| {
            let lev_nm = (1 + 64 + (my_hash(nm).leading_zeros())) as u32 ;
            if left_tree_lev <= lev_nm && lev_nm <= parent_lev {
                let nil = T::nil(st) ;
                // Done: Memoized the recursive calls to tree_of_list_rec.
                let (right_tree, rest) = tree_of_list_rec_memo::<A,X,T,L> ( st, l, rest, &nil, 0 as u32, lev_nm ) ;
                // TODO: Place left_ and right_ trees into articulations (not Boxes), named by name.
                let tree = T::name( st, nm.clone(), Box::new(left_tree.clone()), Box::new(right_tree) ) ;
                tree_of_list_rec_memo::<A,X,T,L> ( st, l, &rest, &tree, lev_nm, parent_lev )
            }
            else {
                let rest = L::name(st, nm.clone(), rest.clone()) ;
                (left_tree.clone(), rest)
            }}
        )
}

pub fn tree_of_list <A:Adapton, X:Hash+Clone, T:TreeT<A,X,X>, L:ListT<A,X>>
    (l:&L, st:&mut A, list:&L::List) -> T::Tree
{
    let nil = T::nil(st) ;
    let (tree, rest) = tree_of_list_rec::<A,X,T,L> (st, l, list, &nil, 0 as u32, u32::max_value()) ;
    assert!( l.is_empty( st, &rest ) );
    tree
}
<|endoftext|>


<commit_before>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, warn, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 4;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        while SPAWNING.load(SeqCst) {
            debug_delay();
            std::thread::yield_now();
        }
        spawn_new_thread(true);
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(SeqCst);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(SeqCst);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    if SPAWNING.compare_and_swap(false, true, SeqCst) == false {
        spawn_new_thread(false);
    }
}

fn spawn_new_thread(is_immortal: bool) {
    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            perform_work(is_immortal);
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            assert!(!is_immortal);
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }

    promise
}
<commit_msg>Spawn 7 default IO threads, remove useless loop<commit_after>//! A simple adaptive threadpool that returns a oneshot future.

use std::{
    collections::VecDeque,
    sync::atomic::AtomicBool,
    thread,
    time::{Duration, Instant},
};

use parking_lot::{Condvar, Mutex};

use crate::{debug_delay, warn, AtomicUsize, Lazy, OneShot, Relaxed, SeqCst};

// This is lower for CI reasons.
#[cfg(windows)]
const MAX_THREADS: usize = 16;

#[cfg(not(windows))]
const MAX_THREADS: usize = 128;

const DESIRED_WAITING_THREADS: usize = 7;

static WAITING_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static TOTAL_THREAD_COUNT: AtomicUsize = AtomicUsize::new(0);
static SPAWNS: AtomicUsize = AtomicUsize::new(0);
static SPAWNING: AtomicBool = AtomicBool::new(false);

macro_rules! once {
    ($args:block) => {
        static E: AtomicBool = AtomicBool::new(false);
        if !E.compare_and_swap(false, true, Relaxed) {
            // only execute this once
            $args;
        }
    };
}

type Work = Box<dyn FnOnce() + Send + 'static>;

struct Queue {
    cv: Condvar,
    mu: Mutex<VecDeque<Work>>,
}

impl Queue {
    fn recv_timeout(&self, duration: Duration) -> Option<Work> {
        let mut queue = self.mu.lock();

        let cutoff = Instant::now() + duration;

        while queue.is_empty() {
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            let res = self.cv.wait_until(&mut queue, cutoff);
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            if res.timed_out() {
                break;
            }
        }

        queue.pop_front()
    }

    fn try_recv(&self) -> Option<Work> {
        let mut queue = self.mu.lock();
        queue.pop_front()
    }

    fn send(&self, work: Work) -> usize {
        let mut queue = self.mu.lock();
        queue.push_back(work);

        let len = queue.len();

        // having held the mutex makes this linearized
        // with the notify below.
        drop(queue);

        self.cv.notify_all();

        len
    }
}

static QUEUE: Lazy<Queue, fn() -> Queue> = Lazy::new(init_queue);

fn init_queue() -> Queue {
    debug_delay();
    for _ in 0..DESIRED_WAITING_THREADS {
        debug_delay();
        spawn_new_thread(true);
    }
    Queue { cv: Condvar::new(), mu: Mutex::new(VecDeque::new()) }
}

fn perform_work(is_immortal: bool) {
    let wait_limit = Duration::from_secs(1);

    let mut performed = 0;
    let mut contiguous_overshoots = 0;

    while is_immortal || performed < 5 || contiguous_overshoots < 3 {
        debug_delay();
        let task_res = QUEUE.recv_timeout(wait_limit);

        if let Some(task) = task_res {
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        while let Some(task) = QUEUE.try_recv() {
            debug_delay();
            WAITING_THREAD_COUNT.fetch_sub(1, SeqCst);
            (task)();
            WAITING_THREAD_COUNT.fetch_add(1, SeqCst);
            performed += 1;
        }

        debug_delay();

        let waiting = WAITING_THREAD_COUNT.load(SeqCst);

        if waiting > DESIRED_WAITING_THREADS {
            contiguous_overshoots += 1;
        } else {
            contiguous_overshoots = 0;
        }
    }
}

// Create up to MAX_THREADS dynamic blocking task worker threads.
// Dynamic threads will terminate themselves if they don't
// receive any work after one second.
fn maybe_spawn_new_thread() {
    debug_delay();
    let total_workers = TOTAL_THREAD_COUNT.load(SeqCst);
    debug_delay();
    let waiting_threads = WAITING_THREAD_COUNT.load(SeqCst);

    if waiting_threads >= DESIRED_WAITING_THREADS
        || total_workers >= MAX_THREADS
    {
        return;
    }

    if SPAWNING.compare_and_swap(false, true, SeqCst) == false {
        spawn_new_thread(false);
    }
}

fn spawn_new_thread(is_immortal: bool) {
    let spawn_id = SPAWNS.fetch_add(1, SeqCst);

    TOTAL_THREAD_COUNT.fetch_add(1, SeqCst);
    let spawn_res = thread::Builder::new()
        .name(format!("sled-io-{}", spawn_id))
        .spawn(move || {
            SPAWNING.store(false, SeqCst);
            debug_delay();
            perform_work(is_immortal);
            TOTAL_THREAD_COUNT.fetch_sub(1, SeqCst);
            assert!(!is_immortal);
        });

    if let Err(e) = spawn_res {
        SPAWNING.store(false, SeqCst);
        once!({
            warn!(
                "Failed to dynamically increase the threadpool size: {:?}.",
                e,
            )
        });
    }
}

/// Spawn a function on the threadpool.
pub fn spawn<F, R>(work: F) -> OneShot<R>
where
    F: FnOnce() -> R + Send + 'static,
    R: Send + 'static,
{
    let (promise_filler, promise) = OneShot::pair();
    let task = move || {
        let result = (work)();
        promise_filler.fill(result);
    };

    let depth = QUEUE.send(Box::new(task));

    if depth > DESIRED_WAITING_THREADS {
        maybe_spawn_new_thread();
    }

    promise
}
<|endoftext|>


<commit_before>//! Topic name

use std::io::{Read, Write};
use std::convert::Into;
use std::ops::Deref;
use std::fmt;
use std::error::Error;
use std::mem;

use regex::Regex;

use encodable::StringEncodeError;
use {Encodable, Decodable};

const TOPIC_NAME_VALIDATE_REGEX: &'static str = r"^(\$?[^/\$]+)?(/[^/\$]*)*$";

lazy_static! {
    static ref TOPIC_NAME_VALIDATOR: Regex = Regex::new(TOPIC_NAME_VALIDATE_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_name(topic_name: &str) -> bool {
    topic_name.is_empty() || topic_name.as_bytes().len() > 65535 || !TOPIC_NAME_VALIDATOR.is_match(&topic_name)
}

/// Topic name
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct TopicName(String);

impl TopicName {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: Into<String>>(topic_name: S) -> Result<TopicName, TopicNameError> {
        let topic_name = topic_name.into();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name))
        } else {
            Ok(TopicName(topic_name))
        }
    }

    /// Creates a new topic name from string without validation
    pub unsafe fn new_unchecked(topic_name: String) -> TopicName {
        TopicName(topic_name)
    }
}

impl Into<String> for TopicName {
    fn into(self) -> String {
        self.0
    }
}

impl Deref for TopicName {
    type Target = TopicNameRef;

    fn deref(&self) -> &TopicNameRef {
        unsafe { TopicNameRef::new_unchecked(&self.0) }
    }
}

impl<'a> Encodable<'a> for TopicName {
    type Err = TopicNameError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicNameError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicNameError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl<'a> Decodable<'a> for TopicName {
    type Err = TopicNameError;
    type Cond = ();

    fn decode_with<R: Read>(reader: &mut R, _rest: Option<()>) -> Result<TopicName, TopicNameError> {
        let topic_name: String = try!(Decodable::decode(reader).map_err(TopicNameError::StringEncodeError));
        TopicName::new(topic_name)
    }
}

/// Errors while parsing topic names
#[derive(Debug)]
pub enum TopicNameError {
    StringEncodeError(StringEncodeError),
    InvalidTopicName(String),
}

impl fmt::Display for TopicNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TopicNameError::StringEncodeError(ref err) => err.fmt(f),
            &TopicNameError::InvalidTopicName(ref topic) => write!(f, "Invalid topic filter ({})", topic),
        }
    }
}

impl Error for TopicNameError {
    fn description(&self) -> &str {
        match self {
            &TopicNameError::StringEncodeError(ref err) => err.description(),
            &TopicNameError::InvalidTopicName(..) => "Invalid topic filter",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &TopicNameError::StringEncodeError(ref err) => Some(err),
            &TopicNameError::InvalidTopicName(..) => None,
        }
    }
}

/// Reference to a topic name
#[derive(Debug, Eq, PartialEq)]
pub struct TopicNameRef(str);

impl TopicNameRef {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: AsRef<str> + ?Sized>(topic_name: &S) -> Result<&TopicNameRef, TopicNameError> {
        let topic_name = topic_name.as_ref();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name.to_owned()))
        } else {
            Ok(unsafe { mem::transmute(topic_name) })
        }
    }

    /// Creates a new topic name from string without validation
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic_name: &S) -> &TopicNameRef {
        mem::transmute(topic_name.as_ref())
    }

    /// Check if this topic name is only for server.
    ///
    /// Topic names that beginning with a '$' character are reserved for servers
    pub fn is_server_specific(&self) -> bool {
        self.0.starts_with('$')
    }
}

impl Deref for TopicNameRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

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

    #[test]
    fn topic_name_sys() {
        let topic_name = "$SYS".to_owned();
        TopicName::new(topic_name).unwrap();

        let topic_name = "$SYS/broker/connection/test.cosm-energy/state".to_owned();
        TopicName::new(topic_name).unwrap();
    }

    #[test]
    fn topic_name_slash() {
        TopicName::new("/").unwrap();
    }

    #[test]
    fn topic_name_basic() {
        TopicName::new("/finance").unwrap();
        TopicName::new("/finance//def").unwrap();
    }
}
<commit_msg>Fix topic name validation regex<commit_after>//! Topic name

use std::io::{Read, Write};
use std::convert::Into;
use std::ops::Deref;
use std::fmt;
use std::error::Error;
use std::mem;

use regex::Regex;

use encodable::StringEncodeError;
use {Encodable, Decodable};

const TOPIC_NAME_VALIDATE_REGEX: &'static str = r"^[^#+]+$";

lazy_static! {
    static ref TOPIC_NAME_VALIDATOR: Regex = Regex::new(TOPIC_NAME_VALIDATE_REGEX).unwrap();
}

#[inline]
fn is_invalid_topic_name(topic_name: &str) -> bool {
    topic_name.is_empty() || topic_name.as_bytes().len() > 65535 || !TOPIC_NAME_VALIDATOR.is_match(&topic_name)
}

/// Topic name
///
/// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718106
#[derive(Debug, Eq, PartialEq, Clone)]
pub struct TopicName(String);

impl TopicName {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: Into<String>>(topic_name: S) -> Result<TopicName, TopicNameError> {
        let topic_name = topic_name.into();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name))
        } else {
            Ok(TopicName(topic_name))
        }
    }

    /// Creates a new topic name from string without validation
    pub unsafe fn new_unchecked(topic_name: String) -> TopicName {
        TopicName(topic_name)
    }
}

impl Into<String> for TopicName {
    fn into(self) -> String {
        self.0
    }
}

impl Deref for TopicName {
    type Target = TopicNameRef;

    fn deref(&self) -> &TopicNameRef {
        unsafe { TopicNameRef::new_unchecked(&self.0) }
    }
}

impl<'a> Encodable<'a> for TopicName {
    type Err = TopicNameError;

    fn encode<W: Write>(&self, writer: &mut W) -> Result<(), TopicNameError> {
        (&self.0[..])
            .encode(writer)
            .map_err(TopicNameError::StringEncodeError)
    }

    fn encoded_length(&self) -> u32 {
        (&self.0[..]).encoded_length()
    }
}

impl<'a> Decodable<'a> for TopicName {
    type Err = TopicNameError;
    type Cond = ();

    fn decode_with<R: Read>(reader: &mut R, _rest: Option<()>) -> Result<TopicName, TopicNameError> {
        let topic_name: String = try!(Decodable::decode(reader).map_err(TopicNameError::StringEncodeError));
        TopicName::new(topic_name)
    }
}

/// Errors while parsing topic names
#[derive(Debug)]
pub enum TopicNameError {
    StringEncodeError(StringEncodeError),
    InvalidTopicName(String),
}

impl fmt::Display for TopicNameError {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            &TopicNameError::StringEncodeError(ref err) => err.fmt(f),
            &TopicNameError::InvalidTopicName(ref topic) => write!(f, "Invalid topic filter ({})", topic),
        }
    }
}

impl Error for TopicNameError {
    fn description(&self) -> &str {
        match self {
            &TopicNameError::StringEncodeError(ref err) => err.description(),
            &TopicNameError::InvalidTopicName(..) => "Invalid topic filter",
        }
    }

    fn cause(&self) -> Option<&Error> {
        match self {
            &TopicNameError::StringEncodeError(ref err) => Some(err),
            &TopicNameError::InvalidTopicName(..) => None,
        }
    }
}

/// Reference to a topic name
#[derive(Debug, Eq, PartialEq)]
pub struct TopicNameRef(str);

impl TopicNameRef {
    /// Creates a new topic name from string
    /// Return error if the string is not a valid topic name
    pub fn new<S: AsRef<str> + ?Sized>(topic_name: &S) -> Result<&TopicNameRef, TopicNameError> {
        let topic_name = topic_name.as_ref();
        if is_invalid_topic_name(&topic_name) {
            Err(TopicNameError::InvalidTopicName(topic_name.to_owned()))
        } else {
            Ok(unsafe { mem::transmute(topic_name) })
        }
    }

    /// Creates a new topic name from string without validation
    pub unsafe fn new_unchecked<S: AsRef<str> + ?Sized>(topic_name: &S) -> &TopicNameRef {
        mem::transmute(topic_name.as_ref())
    }

    /// Check if this topic name is only for server.
    ///
    /// Topic names that beginning with a '$' character are reserved for servers
    pub fn is_server_specific(&self) -> bool {
        self.0.starts_with('$')
    }
}

impl Deref for TopicNameRef {
    type Target = str;

    fn deref(&self) -> &str {
        &self.0
    }
}

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

    #[test]
    fn topic_name_sys() {
        let topic_name = "$SYS".to_owned();
        TopicName::new(topic_name).unwrap();

        let topic_name = "$SYS/broker/connection/test.cosm-energy/state".to_owned();
        TopicName::new(topic_name).unwrap();
    }

    #[test]
    fn topic_name_slash() {
        TopicName::new("/").unwrap();
    }

    #[test]
    fn topic_name_basic() {
        TopicName::new("/finance").unwrap();
        TopicName::new("/finance//def").unwrap();
    }
}
<|endoftext|>


<commit_before>/*
gl/src/gl_wrapper/uniform.rs, 2017-07-13

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

use super::gl_raw;
use self::gl_raw::types::*;

use cgmath::{Vector3, Matrix4};
use cgmath::prelude::*;

use std::ffi::CString;

use gl_wrapper::shader::Program;

pub enum UniformError {
    UniformNotFoundOrGLPrefix,
}

pub trait CreateUniform
    where Self: Sized {

    fn new(name: CString, program: &Program) -> Result<Self, UniformError> {
        let location;

        unsafe {
            location = gl_raw::GetUniformLocation(program.id(), name.as_ptr());
        }

        if location == -1 {
            Err(UniformError::UniformNotFoundOrGLPrefix)
        } else {
            unsafe {
                Ok(Self::from_location(location))
            }
        }

    }

    unsafe fn from_location(location: GLint) -> Self;
}

pub struct UniformVector3 {
    location: GLint,
}

impl CreateUniform for UniformVector3 {
    unsafe fn from_location(location: GLint) -> UniformVector3 {
        UniformVector3 {location}
    }
}

impl UniformVector3 {
    pub fn send(&self, data: &Vector3<f32>) {
        unsafe {
            gl_raw::Uniform3fv(self.location, 1, data.as_ptr());
        }
    }
}

pub struct UniformMatrix4 {
    location: GLint,
}

impl CreateUniform for UniformMatrix4 {
    unsafe fn from_location(location: GLint) -> UniformMatrix4 {
        UniformMatrix4 {location}
    }
}

impl UniformMatrix4 {
    pub fn send(&self, data: &Matrix4<f32>) {
        unsafe {
            gl_raw::UniformMatrix4fv(self.location, 1, gl_raw::FALSE, data.as_ptr());
        }
    }
}
<commit_msg>derive Debug for UniformError<commit_after>/*
gl/src/gl_wrapper/uniform.rs, 2017-07-14

Copyright (c) 2017 Juuso Tuononen

This file is licensed under

Apache License, Version 2.0

or

MIT License
*/

use super::gl_raw;
use self::gl_raw::types::*;

use cgmath::{Vector3, Matrix4};
use cgmath::prelude::*;

use std::ffi::CString;

use gl_wrapper::shader::Program;

#[derive(Debug)]
pub enum UniformError {
    UniformNotFoundOrGLPrefix,
}

pub trait CreateUniform
    where Self: Sized {

    fn new(name: CString, program: &Program) -> Result<Self, UniformError> {
        let location;

        unsafe {
            location = gl_raw::GetUniformLocation(program.id(), name.as_ptr());
        }

        if location == -1 {
            Err(UniformError::UniformNotFoundOrGLPrefix)
        } else {
            unsafe {
                Ok(Self::from_location(location))
            }
        }

    }

    unsafe fn from_location(location: GLint) -> Self;
}

pub struct UniformVector3 {
    location: GLint,
}

impl CreateUniform for UniformVector3 {
    unsafe fn from_location(location: GLint) -> UniformVector3 {
        UniformVector3 {location}
    }
}

impl UniformVector3 {
    pub fn send(&self, data: &Vector3<f32>) {
        unsafe {
            gl_raw::Uniform3fv(self.location, 1, data.as_ptr());
        }
    }
}

pub struct UniformMatrix4 {
    location: GLint,
}

impl CreateUniform for UniformMatrix4 {
    unsafe fn from_location(location: GLint) -> UniformMatrix4 {
        UniformMatrix4 {location}
    }
}

impl UniformMatrix4 {
    pub fn send(&self, data: &Matrix4<f32>) {
        unsafe {
            gl_raw::UniformMatrix4fv(self.location, 1, gl_raw::FALSE, data.as_ptr());
        }
    }
}
<|endoftext|>


<commit_before>use crate::error;
use crate::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

lazy_static! {
    static ref PROPERTY_NAME_REGEX: Regex = Regex::new("[\\w_\\-.]+").unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, PartialEq, Eq)]
pub struct Assertion {
    pub position: Point,
    pub expected_capture_name: String,
}

/// Parse the given source code, finding all of the comments that contain
/// highlighting assertions. Return a vector of (position, expected highlight name)
/// pairs.
pub fn parse_position_comments(
    parser: &mut Parser,
    language: Language,
    source: &[u8],
) -> Result<Vec<Assertion>> {
    let mut result = Vec::new();
    let mut assertion_ranges = Vec::new();

    // Parse the code.
    parser.set_included_ranges(&[]).unwrap();
    parser.set_language(language).unwrap();
    let tree = parser.parse(source, None).unwrap();

    // Walk the tree, finding comment nodes that contain assertions.
    let mut ascending = false;
    let mut cursor = tree.root_node().walk();
    loop {
        if ascending {
            let node = cursor.node();

            // Find every comment node.
            if node.kind().contains("comment") {
                if let Ok(text) = node.utf8_text(source) {
                    let mut position = node.start_position();
                    if position.row == 0 {
                        continue;
                    }

                    // Find the arrow character ("^" or '<-") in the comment. A left arrow
                    // refers to the column where the comment node starts. An up arrow refers
                    // to its own column.
                    let mut has_left_caret = false;
                    let mut has_arrow = false;
                    let mut arrow_end = 0;
                    for (i, c) in text.char_indices() {
                        arrow_end = i + 1;
                        if c == '-' && has_left_caret {
                            has_arrow = true;
                            break;
                        }
                        if c == '^' {
                            has_arrow = true;
                            position.column += i;
                            break;
                        }
                        has_left_caret = c == '<';
                    }

                    // If the comment node contains an arrow and a highlight name, record the
                    // highlight name and the position.
                    if let (true, Some(mat)) =
                        (has_arrow, PROPERTY_NAME_REGEX.find(&text[arrow_end..]))
                    {
                        assertion_ranges.push((node.start_position(), node.end_position()));
                        result.push(Assertion {
                            position: position,
                            expected_capture_name: mat.as_str().to_string(),
                        });
                    }
                }
            }

            // Continue walking the tree.
            if cursor.goto_next_sibling() {
                ascending = false;
            } else if !cursor.goto_parent() {
                break;
            }
        } else if !cursor.goto_first_child() {
            ascending = true;
        }
    }

    // Adjust the row number in each assertion's position to refer to the line of
    // code *above* the assertion. There can be multiple lines of assertion comments,
    // so the positions may have to be decremented by more than one row.
    let mut i = 0;
    for assertion in result.iter_mut() {
        loop {
            let on_assertion_line = assertion_ranges[i..]
                .iter()
                .any(|(start, _)| start.row == assertion.position.row);
            if on_assertion_line {
                assertion.position.row -= 1;
            } else {
                while i < assertion_ranges.len()
                    && assertion_ranges[i].0.row < assertion.position.row
                {
                    i += 1;
                }
                break;
            }
        }
    }

    // The assertions can end up out of order due to the line adjustments.
    result.sort_unstable_by_key(|a| a.position);

    Ok(result)
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let pairs = parse_position_comments(parser, language, contents.as_bytes())?;

    let per_position_index: HashMap<Point, &String> = pairs
        .iter()
        .map(|a| (a.position, &a.expected_capture_name))
        .collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        if **found != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, found, info.name
            )))?
        }
    }
    Ok(())
}
<commit_msg>better name for capture regex<commit_after>use crate::error;
use crate::error::Result;
use lazy_static::lazy_static;
use regex::Regex;
use std::collections::hash_map::HashMap;
use std::fs;
use tree_sitter::{Language, Parser, Point};

lazy_static! {
    static ref CAPTURE_NAME_REGEX: Regex = Regex::new("[\\w_\\-.]+").unwrap();
}

#[derive(Debug, Eq, PartialEq)]
pub struct CaptureInfo {
    pub name: String,
    pub position: Point,
}

#[derive(Debug, PartialEq, Eq)]
pub struct Assertion {
    pub position: Point,
    pub expected_capture_name: String,
}

/// Parse the given source code, finding all of the comments that contain
/// highlighting assertions. Return a vector of (position, expected highlight name)
/// pairs.
pub fn parse_position_comments(
    parser: &mut Parser,
    language: Language,
    source: &[u8],
) -> Result<Vec<Assertion>> {
    let mut result = Vec::new();
    let mut assertion_ranges = Vec::new();

    // Parse the code.
    parser.set_included_ranges(&[]).unwrap();
    parser.set_language(language).unwrap();
    let tree = parser.parse(source, None).unwrap();

    // Walk the tree, finding comment nodes that contain assertions.
    let mut ascending = false;
    let mut cursor = tree.root_node().walk();
    loop {
        if ascending {
            let node = cursor.node();

            // Find every comment node.
            if node.kind().contains("comment") {
                if let Ok(text) = node.utf8_text(source) {
                    let mut position = node.start_position();
                    if position.row == 0 {
                        continue;
                    }

                    // Find the arrow character ("^" or '<-") in the comment. A left arrow
                    // refers to the column where the comment node starts. An up arrow refers
                    // to its own column.
                    let mut has_left_caret = false;
                    let mut has_arrow = false;
                    let mut arrow_end = 0;
                    for (i, c) in text.char_indices() {
                        arrow_end = i + 1;
                        if c == '-' && has_left_caret {
                            has_arrow = true;
                            break;
                        }
                        if c == '^' {
                            has_arrow = true;
                            position.column += i;
                            break;
                        }
                        has_left_caret = c == '<';
                    }

                    // If the comment node contains an arrow and a highlight name, record the
                    // highlight name and the position.
                    if let (true, Some(mat)) =
                        (has_arrow, CAPTURE_NAME_REGEX.find(&text[arrow_end..]))
                    {
                        assertion_ranges.push((node.start_position(), node.end_position()));
                        result.push(Assertion {
                            position: position,
                            expected_capture_name: mat.as_str().to_string(),
                        });
                    }
                }
            }

            // Continue walking the tree.
            if cursor.goto_next_sibling() {
                ascending = false;
            } else if !cursor.goto_parent() {
                break;
            }
        } else if !cursor.goto_first_child() {
            ascending = true;
        }
    }

    // Adjust the row number in each assertion's position to refer to the line of
    // code *above* the assertion. There can be multiple lines of assertion comments,
    // so the positions may have to be decremented by more than one row.
    let mut i = 0;
    for assertion in result.iter_mut() {
        loop {
            let on_assertion_line = assertion_ranges[i..]
                .iter()
                .any(|(start, _)| start.row == assertion.position.row);
            if on_assertion_line {
                assertion.position.row -= 1;
            } else {
                while i < assertion_ranges.len()
                    && assertion_ranges[i].0.row < assertion.position.row
                {
                    i += 1;
                }
                break;
            }
        }
    }

    // The assertions can end up out of order due to the line adjustments.
    result.sort_unstable_by_key(|a| a.position);

    Ok(result)
}

pub fn assert_expected_captures(
    infos: Vec<CaptureInfo>,
    path: String,
    parser: &mut Parser,
    language: Language,
) -> Result<()> {
    let contents = fs::read_to_string(path)?;
    let pairs = parse_position_comments(parser, language, contents.as_bytes())?;

    let per_position_index: HashMap<Point, &String> = pairs
        .iter()
        .map(|a| (a.position, &a.expected_capture_name))
        .collect();

    for info in &infos {
        if !per_position_index.contains_key(&info.position) {
            continue;
        }
        let found = per_position_index.get(&info.position).unwrap();
        if **found != info.name && info.name != "name" {
            Err(error::Error::new(format!(
                "Assertion failed: at {}, found {}, expected {}",
                info.position, found, info.name
            )))?
        }
    }
    Ok(())
}
<|endoftext|>


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

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

use std::process::exit;
use std::process::{Command, Stdio};

use libimagrt::runtime::Runtime;

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") {
                println!("To be implemented");
                //
                // TODO @Kevin: import function aus task_hookrs benutzen, um
                //              stdin auszulesen, und dann auf dem
                //              task_hookrs::task::Task den Trait für die
                //              Umwandlung aufrufen.
                //
            }
            else if subcmd.is_present("delete") {
                println!("To be implemented");
                //
                // Functionality to delete Entry in the store
                //
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                panic!("Reached unreachable Code");
            }
        },
        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 mut tw_process = Command::new("/usr/local/bin/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");
		}
            },
                _ => panic!("Reached unreachable Code"),
        }

}

<commit_msg>changed /usr/bin/local/task to task<commit_after>extern crate clap;
extern crate glob;
extern crate task_hookrs;
#[macro_use] extern crate log;
extern crate semver;
extern crate toml;
#[macro_use] extern crate version;

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

use std::process::exit;
use std::process::{Command, Stdio};

use libimagrt::runtime::Runtime;

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") {
                println!("To be implemented");
                //
                // TODO @Kevin: import function aus task_hookrs benutzen, um
                //              stdin auszulesen, und dann auf dem
                //              task_hookrs::task::Task den Trait für die
                //              Umwandlung aufrufen.
                //
            }
            else if subcmd.is_present("delete") {
                println!("To be implemented");
                //
                // Functionality to delete Entry in the store
                //
            }
            else {
                // Should not be possible, as one argument is required via
                // ArgGroup
                panic!("Reached unreachable Code");
            }
        },
        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 mut 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");
		}
            },
                _ => panic!("Reached unreachable Code"),
        }

}

<|endoftext|>