Documentation
/*
==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--==--

Dia-Args

Copyright (C) 2018-2019, 2021-2025  Anonymous

There are several releases over multiple years,
they are listed as ranges, such as: "2018-2019".

This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License
along with this program.  If not, see <https://www.gnu.org/licenses/>.

::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--::--
*/

//! # Stream

use {
    core::mem,
    std::io::{Bytes, Error, ErrorKind, Read},
    crate::{
        Result,
        read_only_u64::ReadOnlyU64,
    },
};

/// # Stream
#[derive(Debug)]
pub struct Stream<R> where R: Read {
    src: Bytes<R>,
    // Used for formatting error messages
    max_size: ReadOnlyU64,
    // Used for max_size
    limit: usize,
}

impl<R> Stream<R> where R: Read {

    /// # Makes new instance
    pub fn make(src: R, max_size: u64) -> Result<Self> {
        let limit = if mem::size_of::<usize>() >= mem::size_of::<u64>() || usize::max_value() as u64 >= max_size {
            max_size as usize
        } else {
            return Err(Error::new(ErrorKind::InvalidInput, format!(
                "max_size is too large: {max_size}, max allowed: {max_size_allowed}", max_size=max_size, max_size_allowed=usize::max_value(),
            )));
        };
        Ok(Self {
            src: src.bytes(),
            max_size: max_size.into(),
            limit,
        })
    }

}

impl<R> Iterator for Stream<R> where R: Read {

    type Item = Result<String>;

    fn next(&mut self) -> Option<Self::Item> {
        let mut buf = Vec::with_capacity(self.limit.min(1024));

        /// # Parses buffer
        ///
        /// - Buffer size is subtracted from `limit`.
        /// - `if_empty` is used if buffer is empty.
        fn parse_buf<F>(buf: Vec<u8>, limit: &mut usize, if_empty: F) -> Option<Result<String>> where F: FnOnce() -> Option<Result<String>> {
            match buf.len() {
                0 => if_empty(),
                buf_len => {
                    *limit = limit.saturating_sub(buf_len);
                    match String::from_utf8(buf) {
                        Ok(s) => Some(Ok(s)),
                        Err(err) => Some(Err(Error::new(ErrorKind::Other, err))),
                    }
                },
            }
        }

        loop {
            match self.src.next() {
                Some(Ok(0)) => return parse_buf(buf, &mut self.limit, || Some(Ok(String::new()))),
                Some(Ok(b)) => if buf.len() < self.limit {
                    buf.push(b);
                } else {
                    self.limit = 0;
                    return Some(Err(Error::new(
                        ErrorKind::InvalidData, format!("Input data is too large, max allowed: {} bytes", *self.max_size),
                    )));
                },
                Some(Err(err)) => {
                    self.limit = self.limit.saturating_sub(buf.len());
                    return Some(Err(err));
                },
                None => return parse_buf(buf, &mut self.limit, || None),
            };
        }
    }

}