ssv 0.1.0

SSV means Space-Separated Values, and is an alternative to CSV.
Documentation
use std::fmt::Debug;
use std::io::{BufRead, BufReader, Bytes, Read};
use std::ops::Deref;

pub trait Domain: Eq + Clone + Debug {
    type Element: Copy + Eq + Debug;
    type ElementIterator<R: Read>: Iterator<Item = std::io::Result<Self::Element>>;
    type String: DomainString<Self::Element> + Deref<Target = Self::StringSlice>;
    type StringSlice: DomainStringSlice<Self::Element> + ToOwned<Owned = Self::String> + ?Sized;

    const LF: Self::Element;
    const CR: Self::Element;
    const QUOTE: Self::Element;
    const SPACE: Self::Element;
    const HASH: Self::Element;

    fn is_spacing_element(element: Self::Element) -> bool;
    fn is_valid_spacing(spacing: &Self::StringSlice) -> bool;
    fn element_iterator<R: Read>(inner: R) -> Self::ElementIterator<R>;
}

pub trait DomainString<E>: Sized + Clone + Eq + Debug {
    fn new() -> Self;
    fn push(&mut self, element: E);
    fn quotes(length: usize) -> Self;

    fn from_element(element: E) -> Self {
        let mut string = Self::new();
        string.push(element);
        string
    }
}

pub trait DomainStringSlice<E> {
    fn as_bytes(&self) -> &[u8];
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct BytesDomain;
impl Domain for BytesDomain {
    type Element = u8;
    type ElementIterator<R: Read> = Bytes<R>;
    type String = Vec<u8>;
    type StringSlice = [u8];

    const LF: Self::Element = b'\n';
    const CR: Self::Element = b'\r';
    const QUOTE: Self::Element = b'"';
    const SPACE: Self::Element = b' ';
    const HASH: Self::Element = b'#';

    fn is_spacing_element(element: Self::Element) -> bool {
        matches!(element, b' ' | b'\t')
    }

    fn is_valid_spacing(spacing: &Self::StringSlice) -> bool {
        !spacing.is_empty() && spacing.iter().all(|byte| Self::is_spacing_element(*byte))
    }

    fn element_iterator<R: Read>(inner: R) -> Self::ElementIterator<R> {
        inner.bytes()
    }
}

impl DomainString<u8> for Vec<u8> {
    fn new() -> Self {
        Vec::new()
    }

    fn push(&mut self, element: u8) {
        Vec::push(self, element);
    }

    fn quotes(length: usize) -> Self {
        [BytesDomain::QUOTE].repeat(length)
    }
}

impl DomainStringSlice<u8> for [u8] {
    fn as_bytes(&self) -> &[u8] {
        self
    }
}

#[derive(Clone, Copy, PartialEq, Eq, Debug)]
pub struct CharsDomain;
impl Domain for CharsDomain {
    type Element = char;
    type ElementIterator<R: Read> = Chars<R>;
    type String = String;
    type StringSlice = str;

    const LF: Self::Element = '\n';
    const CR: Self::Element = '\r';
    const QUOTE: Self::Element = '"';
    const SPACE: Self::Element = ' ';
    const HASH: Self::Element = '#';

    fn is_spacing_element(element: Self::Element) -> bool {
        matches!(element, ' ' | '\t')
    }

    fn is_valid_spacing(spacing: &Self::StringSlice) -> bool {
        !spacing.is_empty() && spacing.chars().all(Self::is_spacing_element)
    }

    fn element_iterator<R: Read>(inner: R) -> Self::ElementIterator<R> {
        Chars {
            inner: BufReader::new(inner),
            chars: None,
        }
    }
}

impl DomainString<char> for String {
    fn new() -> Self {
        String::new()
    }

    fn push(&mut self, element: char) {
        String::push(self, element);
    }

    fn quotes(length: usize) -> Self {
        Self::from_element(CharsDomain::QUOTE).repeat(length)
    }
}

impl DomainStringSlice<char> for str {
    fn as_bytes(&self) -> &[u8] {
        self.as_bytes()
    }
}

pub struct Chars<R: Read> {
    inner: BufReader<R>,
    chars: Option<std::vec::IntoIter<char>>,
}

impl<R: Read> Chars<R> {
    pub fn new(reader: R) -> Self {
        Chars {
            inner: BufReader::new(reader),
            chars: None,
        }
    }
}

impl<R: Read> Iterator for Chars<R> {
    type Item = Result<char, std::io::Error>;

    fn next(&mut self) -> Option<Self::Item> {
        if let Some(ref mut chars) = self.chars {
            if let Some(char) = chars.next() {
                return Some(Ok(char));
            }
        }

        let mut buf = String::new();
        if let Err(err) = self.inner.read_line(&mut buf) {
            return Some(Err(err));
        }

        let mut chars: std::vec::IntoIter<char> = buf.chars().collect::<Vec<_>>().into_iter();
        if let Some(char) = chars.next() {
            self.chars = Some(chars);
            Some(Ok(char))
        } else {
            None
        }
    }
}

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

    #[test]
    fn chars() {
        let reader: &[u8] = b"abc def\n123 456";

        let chars = Chars::new(reader);

        let vec: Result<Vec<char>, std::io::Error> = chars.collect();
        assert_eq!(vec.unwrap(), "abc def\n123 456".chars().collect::<Vec<_>>(),);
    }

    #[test]
    fn chars_utf8() {
        let reader: &[u8] = b"\xC3\xB3rg\xC3\xA3o";

        let chars = Chars::new(reader);

        let vec: Result<Vec<char>, std::io::Error> = chars.collect();
        assert_eq!(vec.unwrap(), "órgão".chars().collect::<Vec<_>>(),);
    }

    #[test]
    fn chars_utf8_error() {
        let reader: &[u8] = b"a\nb\xFF "; // Invalid UTF-8

        let mut chars = Chars::new(reader);

        assert_eq!(chars.next().unwrap().unwrap(), 'a');
        assert_eq!(chars.next().unwrap().unwrap(), '\n');
        let error = chars.next().unwrap().unwrap_err();
        assert_eq!(error.kind(), std::io::ErrorKind::InvalidData);
    }
}