1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
/* mod.rs
 *
 * Developed by Tim Walls <tim.walls@snowgoons.com>
 * Copyright (c) All Rights Reserved, Tim Walls
 */
//! Simple IO traits (a very, very, very cutdown version of std::io).  In due
//! course hopefully somewhat /less/ cutdown, and maybe even derived from
//! std::io in the style of the `core_io` crate, but right now this is what
//! we've got.
//!
//! (We can't use `core_io` at the moment because the build scripts do not
//! recognise our custom toolchain; if we ever get to a place where the
//! regular Rust toolchain works on AVR again, we may be able to revisit this.)

// Imports ===================================================================
use avr_oxide::OxideResult::{Ok};


// Declarations ==============================================================
/// Errors that can result from our IO routines
#[cfg_attr(not(target_arch="avr"), derive(Debug))]
#[cfg_attr(target_arch="avr", derive(ufmt::derive::uDebug))]
pub enum IoError {
  /// We have reached the end of a file for reading
  EndOfFile,

  /// We have no remaining free space for writing
  NoFreeSpace,

  /// Generic IO error
  Unknown,

  /// Write not allowed (read-only device)
  WriteProhibited,

  /// Read not allowed (write-only device)
  ReadProhibited,

  /// The device is not ready (or formatted)
  DeviceNotReady,

  /// The requested read/write was out of range
  OutOfRange,

  /// The requested resource already exists
  Exists,

  /// The requested resource does not exist
  NotFound,

  /// There was a mismatch between endianess representations (e.g. a
  /// big-endian formatted device was read on a little-endian processor)
  EndianMismatch,

  /// The underlying filesystem (or whatever) has not been formatted
  Unformatted,

  /// Bad or conflicting options were passed to an IO call
  BadOptions
}

pub type Result<T> = avr_oxide::OxideResult<T,IoError>;

pub trait Read {
  fn read(&mut self, _buf: &mut [u8]) -> avr_oxide::io::Result<usize>;

  fn read_exact(&mut self, buf: &mut [u8]) -> avr_oxide::io::Result<()> {
    let mut offset = 0usize;

    while offset < buf.len() {
      let bytes_read = self.read(&mut buf[offset..])?;

      offset += bytes_read;
    }

    Ok(())
  }
}

pub trait Write {
  fn flush(&mut self) -> avr_oxide::io::Result<()>;
  fn write_buffered(&mut self, buf:&[u8]) -> avr_oxide::io::Result<usize>;

  fn write(&mut self, buf: &[u8]) -> avr_oxide::io::Result<usize> {
    let bytes = self.write_buffered(buf)?;
    self.flush()?;
    Ok(bytes)
  }

  fn write_all(&mut self, buf: &[u8]) -> avr_oxide::io::Result<()> {
    let mut offset = 0usize;

    while offset < buf.len() {
      let bytes_written = self.write_buffered(&buf[offset..])?;

      offset += bytes_written;
    }
    self.flush()?;

    Ok(())
  }
}


// Code ======================================================================

#[cfg(not(target_arch="avr"))]
impl Read for std::io::Stdin {
  fn read(&mut self, buf: &mut [u8]) -> avr_oxide::io::Result<usize> {
    match std::io::Read::read(self, buf) {
      std::result::Result::Ok(b) => avr_oxide::OxideResult::Ok(b),
      std::result::Result::Err(_e) => avr_oxide::OxideResult::Err(IoError::Unknown)
    }
  }
}
#[cfg(not(target_arch="avr"))]
impl Write for std::io::Stdout {
  fn write_buffered(&mut self, buf: &[u8]) -> avr_oxide::io::Result<usize> {
    match std::io::Write::write(self, buf) {
      std::result::Result::Ok(b) => avr_oxide::OxideResult::Ok(b),
      std::result::Result::Err(_e) => avr_oxide::OxideResult::Err(IoError::Unknown)
    }
  }

  fn flush(&mut self) -> Result<()> {
    std::io::Write::flush(self);
    avr_oxide::OxideResult::Ok(())
  }
}
#[cfg(not(target_arch="avr"))]
impl Write for std::io::Stderr {
  fn write_buffered(&mut self, buf: &[u8]) -> Result<usize> {
    match std::io::Write::write(self, buf) {
      std::result::Result::Ok(b) => avr_oxide::OxideResult::Ok(b),
      std::result::Result::Err(_e) => avr_oxide::OxideResult::Err(IoError::Unknown)
    }
  }

  fn flush(&mut self) -> Result<()> {
    std::io::Write::flush(self);
    avr_oxide::OxideResult::Ok(())
  }
}

// Tests =====================================================================