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 #[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}