Skip to main content

relibc/header/stdio/
reader.rs

1use super::{FILE, SEEK_SET, fseek_locked, ftell_locked};
2use crate::{
3    c_str::{CStr, Kind, NulStr, Thin, WStr, Wide},
4    header::{
5        errno::EILSEQ,
6        stdlib::MB_CUR_MAX,
7        wchar::{get_char_encoded_length, mbrtowc},
8        wctype::WEOF,
9    },
10    io::Read,
11    platform::{
12        ERRNO,
13        types::{c_char, off_t, wchar_t, wint_t},
14    },
15};
16use core::{
17    iter::Iterator,
18    marker::PhantomData,
19    ptr::{self},
20};
21
22pub struct BufferReader<'a, T: Kind> {
23    buf: NulStr<'a, T>,
24}
25
26impl<'a> From<WStr<'a>> for BufferReader<'a, Wide> {
27    fn from(buff: WStr<'a>) -> Self {
28        BufferReader { buf: buff }
29    }
30}
31
32impl<'a> From<CStr<'a>> for BufferReader<'a, Thin> {
33    fn from(buff: CStr<'a>) -> Self {
34        BufferReader { buf: buff }
35    }
36}
37
38impl<'a, T: Kind> Iterator for BufferReader<'a, T> {
39    type Item = Result<T::Char, i32>;
40
41    fn next(&mut self) -> Option<Self::Item> {
42        self.buf.split_first().map(|(c, r)| {
43            self.buf = r;
44            Ok(c)
45        })
46    }
47}
48
49pub struct FileReader<'a, T: Kind> {
50    f: &'a mut FILE,
51    position: off_t,
52    phantom: PhantomData<T>,
53}
54
55impl<'a, T: Kind> FileReader<'a, T> {
56    // Gets the wchar at the current position
57    #[inline]
58    fn get_curret_char(&mut self) -> Result<Option<(T::Char, usize)>, i32> {
59        if T::IS_THIN_NOT_WIDE {
60            let mut buf: [u8; 1] = [0];
61            match self.f.read(&mut buf) {
62                Ok(0) => Ok(None),
63                Ok(n) => Ok(Some((T::Char::from(buf[0]), n))),
64                Err(_) => Err(-1),
65            }
66        } else {
67            let buf = &mut [0; MB_CUR_MAX as usize];
68            let mut encoded_length = 0;
69            let mut bytes_read = 0;
70
71            loop {
72                match self.f.read(&mut buf[bytes_read..bytes_read + 1]) {
73                    Ok(0) => return Ok(None),
74                    Ok(_) => {}
75                    Err(_) => return Err(-1),
76                }
77
78                bytes_read += 1;
79
80                if bytes_read == 1 {
81                    encoded_length = if let Some(el) = get_char_encoded_length(buf[0]) {
82                        el
83                    } else {
84                        ERRNO.set(EILSEQ);
85                        return Self::get_char_from_wint(WEOF).map(|c| Some((c, 0)));
86                    };
87                }
88
89                if bytes_read >= encoded_length {
90                    break;
91                }
92            }
93
94            let mut wc: wchar_t = 0;
95            unsafe {
96                mbrtowc(
97                    &raw mut wc,
98                    buf.as_ptr().cast::<c_char>(),
99                    encoded_length,
100                    ptr::null_mut(),
101                );
102            }
103
104            Self::get_char_from_wint(wc as wint_t).map(|c| Some((c, encoded_length)))
105        }
106    }
107
108    fn get_char_from_wint(wc: wint_t) -> Result<T::Char, i32> {
109        if let Some(wc_char) = T::chars_from_bytes(&wc.to_be_bytes())
110            && wc_char.len() == 1
111        {
112            Ok(wc_char[0])
113        } else {
114            Err(-1)
115        }
116    }
117}
118
119impl<'a, T: Kind> Iterator for FileReader<'a, T> {
120    type Item = Result<T::Char, i32>;
121
122    fn next(&mut self) -> Option<Self::Item> {
123        unsafe { fseek_locked(self.f, self.position, SEEK_SET) };
124
125        match self.get_curret_char() {
126            Ok(Some((wc, encoded_length))) => {
127                unsafe { fseek_locked(self.f, self.position, SEEK_SET) };
128                self.position += encoded_length as off_t;
129                Some(Ok(wc))
130            }
131            Ok(None) => None,
132            Err(e) => Some(Err(e)),
133        }
134    }
135}
136
137impl<'a, T: Kind> From<&'a mut FILE> for FileReader<'a, T> {
138    fn from(f: &'a mut FILE) -> Self {
139        let position = unsafe { ftell_locked(f) } as off_t;
140        FileReader {
141            f,
142            position,
143            phantom: PhantomData::<T>,
144        }
145    }
146}
147
148pub enum Reader<'a, T: Kind> {
149    FILE(FileReader<'a, T>, PhantomData<T>),
150    BUFFER(BufferReader<'a, T>),
151}
152
153impl<'a, T: Kind> Iterator for Reader<'a, T> {
154    type Item = Result<T::Char, i32>;
155
156    fn next(&mut self) -> Option<Self::Item> {
157        match self {
158            Self::FILE(r, _) => r.next(),
159            Self::BUFFER(r) => r.next(),
160        }
161    }
162}
163
164impl<'a, T: Kind> From<&'a mut FILE> for Reader<'a, T> {
165    fn from(f: &'a mut FILE) -> Self {
166        Self::FILE(f.into(), PhantomData::<T>)
167    }
168}
169
170impl<'a> From<WStr<'a>> for Reader<'a, Wide> {
171    fn from(buff: WStr<'a>) -> Self {
172        Self::BUFFER(buff.into())
173    }
174}
175
176impl<'a> From<CStr<'a>> for Reader<'a, Thin> {
177    fn from(buff: CStr<'a>) -> Self {
178        Self::BUFFER(buff.into())
179    }
180}