use crate::TextString;
use basic_text_internals::unicode::CGJ;
use basic_text_internals::{is_basic_text, is_basic_text_end};
use std::borrow::Cow;
use std::io::{self, BufRead};
pub trait BufReadText: BufRead {
fn read_text_line(&mut self, buf: &mut TextString) -> io::Result<usize> {
let len = self.read_line(&mut buf.0)?;
if !is_basic_text(&buf.0) {
buf.0.clear();
return Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid Basic Text",
));
}
Ok(len)
}
fn read_text_line_lossy(&mut self, buf: &mut TextString) -> io::Result<usize> {
let len = self.read_line(&mut buf.0)?;
if let Cow::Owned(text) = TextString::from_text_lossy(&buf.0) {
buf.0 = text.0;
}
Ok(len)
}
fn text_lines(self) -> TextLines<Self>
where
Self: Sized,
{
TextLines { buf: self }
}
fn text_lines_lossy(self) -> TextLinesLossy<Self>
where
Self: Sized,
{
TextLinesLossy { buf: self }
}
}
#[derive(Debug)]
pub struct TextLines<B> {
buf: B,
}
impl<B: BufReadText> Iterator for TextLines<B> {
type Item = io::Result<TextString>;
fn next(&mut self) -> Option<io::Result<TextString>> {
let mut buf = TextString::new();
match self.buf.read_text_line(&mut buf) {
Ok(0) => None,
Ok(_n) => {
debug_assert!(buf.0.ends_with('\n'));
buf.0.pop();
debug_assert!(!buf.0.ends_with('\r'));
if let Some(c) = buf.0.chars().next_back() {
if !is_basic_text_end(c) {
return Some(Err(io::Error::new(
io::ErrorKind::InvalidData,
"stream did not contain valid Basic Text lines",
)));
}
}
Some(Ok(buf))
}
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug)]
pub struct TextLinesLossy<B> {
buf: B,
}
impl<B: BufReadText> Iterator for TextLinesLossy<B> {
type Item = io::Result<TextString>;
fn next(&mut self) -> Option<io::Result<TextString>> {
let mut buf = TextString::new();
match self.buf.read_text_line_lossy(&mut buf) {
Ok(0) => None,
Ok(_n) => {
debug_assert!(buf.0.ends_with('\n'));
buf.0.pop();
debug_assert!(!buf.0.ends_with('\r'));
if let Some(c) = buf.0.chars().next_back() {
if !is_basic_text_end(c) {
buf.0.push(CGJ);
}
}
Some(Ok(buf))
}
Err(e) => Some(Err(e)),
}
}
}
impl<T: BufRead> BufReadText for T {}