c2r_helpers/
lib.rs

1use std::io;
2
3// From manpages:
4// "fgetc() reads the next character from stream and returns it as an unsigned char cast to an int,
5// or EOF on end of file or error."
6//
7// [Q] is the return type ok? the callers would have to handle "Result"
8pub fn fgetc(f: &mut dyn io::Read) -> io::Result<i32> {
9    let mut buffer = [0; 1];
10    match f.read(&mut buffer) {
11        Ok(0) => Ok(-1),
12        Ok(_) => Ok(buffer[0] as i32),
13        Err(e) => Err(e),
14    }
15}
16
17#[test]
18fn test_fgetc() {
19    use std::io::Cursor;
20
21    let data = "AB".as_bytes();
22    let mut cursor = Cursor::new(data);
23    assert_eq!(fgetc(&mut cursor).unwrap(), 'A' as i32);
24    assert_eq!(fgetc(&mut cursor).unwrap(), 'B' as i32);
25    assert_eq!(fgetc(&mut cursor).unwrap(), -1);
26}
27
28// From manpages;
29// "The function feof() tests the end-of-file indicator for the stream pointed to by stream,
30// returning nonzero if it is set.  The end-of-file indicator can be cleared only by the function
31// clearerr()."
32// "The feof() function returns nonzero if the end-of-file indicator is set for stream; otherwise,
33// it returns zero."
34//
35// [Q] I am not sure how to "set end-of-file indicator for the stream" here, so not 100%
36// equivalent.
37// [Q] should we just use the unwrap() internally and return a i32, instead of returning a Result<i32> here?
38pub fn feof(f: &mut dyn io::BufRead) -> io::Result<i32> {
39    f.fill_buf().map(|b| if b.is_empty() { 1 } else { 0 })
40}
41
42#[test]
43fn test_feof() {
44    use std::io::Cursor;
45
46    let data = "AB".as_bytes();
47    let mut cursor = Cursor::new(data);
48    assert_eq!(feof(&mut cursor).unwrap(), 0);
49    let _ = fgetc(&mut cursor).unwrap();
50    assert_eq!(feof(&mut cursor).unwrap(), 0);
51    let _ = fgetc(&mut cursor).unwrap();
52    assert_ne!(feof(&mut cursor).unwrap(), 0);
53    let eof = fgetc(&mut cursor).unwrap();
54    assert_eq!(eof, -1);
55}