1// Copyright (c) 2023 Huawei Device Co., Ltd.
2// Licensed under the Apache License, Version 2.0 (the "License");
3// you may not use this file except in compliance with the License.
4// You may obtain a copy of the License at
5//
6//     http://www.apache.org/licenses/LICENSE-2.0
7//
8// Unless required by applicable law or agreed to in writing, software
9// distributed under the License is distributed on an "AS IS" BASIS,
10// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11// See the License for the specific language governing permissions and
12// limitations under the License.
13
14mod io_reader;
15pub(crate) use io_reader::IoReader;
16
17mod slice_reader;
18pub(crate) use slice_reader::SliceReader;
19
20/// `BytesReader` provides the basic byte read interface, such as `next`,
21/// `peek`, `index`. Users can obtain the next byte or the current read
22/// position according to these interfaces.
23pub(crate) trait BytesReader {
24    /// Errors that may occur during reading, usually in the I\O process.
25    type Error: Into<Box<dyn std::error::Error>>;
26
27    /// Get the next character and move the cursor to the next place.
28    fn next(&mut self) -> Result<Option<u8>, Self::Error>;
29
30    /// Get the next character, but don't move the cursor. So the next read
31    /// will get the same character.
32    fn peek(&mut self) -> Result<Option<u8>, Self::Error>;
33
34    /// Discard the next character and move the cursor to the next place.
35    fn discard(&mut self);
36
37    /// Get the current cursor position and return it as usize.
38    fn index(&self) -> usize;
39
40    /// Get the current cursor position and return it as `Position`.
41    fn position(&self) -> Position;
42}
43
44/// `Cacheable` provides some byte cache interfaces for caching a portion of
45/// contiguous bytes in a byte stream.
46pub(crate) trait Cacheable: BytesReader {
47    /// Start the cache operation. This interface needs to be used with
48    /// `end_caching` or `take_cached_data`.
49    fn start_caching(&mut self);
50
51    /// Get the length of the cached bytes. Since the logic of caching
52    /// operations is implementation-dependent, we provide an interface that
53    /// uses mutable references here.
54    fn cached_len(&mut self) -> Option<usize>;
55
56    /// Get a slice of the cached bytes. Since the logic of caching operations
57    /// is implementation-dependent, we provide an interface that uses mutable
58    /// references here.
59    fn cached_slice(&mut self) -> Option<&[u8]>;
60
61    /// Get a `Vec` of the cached bytes. Since the logic of caching operations
62    /// is implementation-dependent, we provide an interface that uses mutable
63    /// references here.
64    fn cached_data(&mut self) -> Option<Vec<u8>>;
65
66    /// End the cache operation. This interface needs to be used with
67    /// `start_caching`.
68    fn end_caching(&mut self);
69
70    /// End the cache operation and return the cached bytes. This interface
71    /// needs to be used with `start_caching`.
72    fn take_cached_data(&mut self) -> Option<Vec<u8>>;
73}
74
75/// `RemainderCountable` provides the interface related to the remainder.
76pub(crate) trait RemainderCountable: BytesReader {
77    /// Get the length of the remainder.
78    fn remainder_len(&self) -> usize;
79
80    /// Get a slice of the remainder.
81    fn remainder_slice(&self) -> &[u8];
82
83    /// Get a `Vec<u8>` of the remainder.
84    fn remainder_data(&self) -> Vec<u8>;
85}
86
87/// `NBytesReadable` provides interfaces to read 'n' bytes at one time.
88pub(crate) trait NBytesReadable: BytesReader {
89    /// Read the next 'n' bytes and move the cursor to the next nth position.
90    /// If there are not enough bytes remaining to satisfy 'n', return `None`
91    /// and do nothing.
92    fn next_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error>;
93
94    /// Get the next 'n' bytes and do not move the cursor. If there are not
95    /// enough bytes remaining to satisfy 'n', return `None` and do nothing.
96    fn peek_n(&mut self, n: usize) -> Result<Option<&[u8]>, Self::Error>;
97
98    /// Discard the next 'n' bytes and move the cursor to the next nth position.
99    /// If there are not enough bytes remaining to satisfy 'n', do nothing.
100    fn discard_n(&mut self, n: usize);
101}
102
103/// Position information which expressed in row and column.
104#[derive(Clone)]
105pub(crate) struct Position {
106    line: usize,
107    column: usize,
108}
109
110impl Position {
111    /// Create a `Position` from the given line and column.
112    #[inline]
113    pub(crate) fn new(line: usize, column: usize) -> Self {
114        Self { line, column }
115    }
116
117    /// Get line.
118    #[inline]
119    pub(crate) fn line(&self) -> usize {
120        self.line
121    }
122
123    /// Get column.
124    #[inline]
125    pub(crate) fn column(&self) -> usize {
126        self.column
127    }
128}
129
130#[cfg(test)]
131mod ut_position {
132    use super::Position;
133
134    /// UT test for `Position::new`.
135    ///
136    /// # Title
137    /// ut_position_new
138    ///
139    /// # Brief
140    /// 1. Call `Position::new` to create a `Position`.
141    /// 2. Check if the results are correct.
142    #[test]
143    fn ut_position_new() {
144        let position = Position::new(1, 1);
145        assert_eq!(position.line, 1);
146        assert_eq!(position.column, 1);
147    }
148
149    /// UT test for `Position::line`.
150    ///
151    /// # Title
152    /// ut_position_line
153    ///
154    /// # Brief
155    /// 1. Create a `Position`.
156    /// 2. Call `Position::line` to get the line number of `Position`.
157    /// 3. Check if the results are correct.
158    #[test]
159    fn ut_position_line() {
160        let position = Position::new(1, 1);
161        assert_eq!(position.line(), 1);
162    }
163
164    /// UT test for `Position::column`.
165    ///
166    /// # Title
167    /// ut_position_column
168    ///
169    /// # Brief
170    /// 1. Create a `Position`.
171    /// 2. Call `Position::column` to get the column number of `Position`.
172    /// 3. Check if the results are correct.
173    #[test]
174    fn ut_position_column() {
175        let position = Position::new(1, 1);
176        assert_eq!(position.column(), 1);
177    }
178
179    /// UT test case for `Position::clone`.
180    ///
181    /// # Title
182    /// ut_position_clone
183    ///
184    /// # Brief
185    /// 1. Create a `Position`.
186    /// 2. Call `Position::clone` to get a copy of `Position`.
187    /// 3. Check if the results are correct.
188    #[allow(clippy::redundant_clone)]
189    #[test]
190    fn ut_position_clone() {
191        let position = Position::new(1, 1);
192        let position = position.clone();
193        assert_eq!(position.line, 1);
194        assert_eq!(position.column, 1);
195    }
196}
197