Begin getting docs in order

This commit is contained in:
Nathan Fisher 2024-05-03 01:10:04 -04:00
parent d203aaf5d3
commit 13fda08e1b
3 changed files with 61 additions and 27 deletions

View File

@ -1,13 +1,30 @@
pub use {
use {
super::B64Alphabet,
std::io::{self, ErrorKind, Read, Write},
std::{
fmt,
io::{self, ErrorKind, Read, Write},
num::TryFromIntError,
},
};
#[derive(Debug)]
/// Errors which might possibly occur while decoding base64 encoded data
pub enum Error {
Io(io::Error),
IllegalChar(char),
MissingPadding,
IntError(TryFromIntError),
}
impl fmt::Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Io(e) => write!(f, "{e}"),
Self::IllegalChar(c) => write!(f, "Illegal Character ({c})"),
Self::MissingPadding => write!(f, "Missing Padding"),
Self::IntError(e) => write!(f, "Int Error: {e}"),
}
}
}
impl From<io::Error> for Error {
@ -22,6 +39,22 @@ impl From<char> for Error {
}
}
impl From<TryFromIntError> for Error {
fn from(value: TryFromIntError) -> Self {
Self::IntError(value)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Io(e) => Some(e),
Self::IntError(e) => Some(e),
_ => None,
}
}
}
pub struct Decoder<R: Read, W: Write> {
reader: R,
writer: W,
@ -37,14 +70,24 @@ impl<R: Read, W: Write> Decoder<R, W> {
}
}
/// Decodes the bytes provided by `self.reader` and writes the resulting
/// bytes into `self.writer`.
/// # Errors
/// - io failure will return `Error::Io`
/// - a character not in the alphabet, or encountering any character after
/// the first occurance of the padding character, will return `Error::IllegalChar`
/// - if the reader comes up short of the final four byte block will return
/// `Error::MissingPadding`
/// - `intError` should never be returned. If this error is recieved the code
/// is somehow broken. Please file a bug.
pub fn decode(&mut self) -> Result<(), Error> {
loop {
let mut ibuf = [0_u8; 4];
let mut obuf = [0_u8; 3];
let mut in_buf = [0_u8; 4];
let mut out_buf = [0_u8; 3];
let mut num = 0_u32;
let mut n_bytes = 0;
loop {
n_bytes += match self.reader.read(&mut ibuf) {
n_bytes += match self.reader.read(&mut in_buf) {
Ok(n) => n,
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
Err(e) => return Err(e.into()),
@ -57,7 +100,7 @@ impl<R: Read, W: Write> Decoder<R, W> {
_ => return Err(Error::MissingPadding),
}
let mut bytes = 0;
for (i, &c) in ibuf.iter().enumerate() {
for (i, &c) in in_buf.iter().enumerate() {
let c = c.into();
num <<= 6;
if c == self.alphabet.pad() {
@ -69,15 +112,15 @@ impl<R: Read, W: Write> Decoder<R, W> {
let Some(idx) = self.alphabet.get(c) else {
return Err(Error::IllegalChar(c));
};
num |= idx as u32;
num |= u32::try_from(idx)?;
bytes += 1;
}
let olen = bytes * 6 / 8;
for i in (0..3).rev() {
obuf[i] = (num & 0xff) as u8;
out_buf[i] = (num & 0xff) as u8;
num >>= 8;
}
self.writer.write_all(&mut obuf[0..olen])?;
self.writer.write_all(&out_buf[0..olen])?;
}
Ok(())
}

View File

@ -1,4 +1,4 @@
pub use {
use {
super::B64Alphabet,
std::{
fmt::{self, Write},
@ -49,6 +49,8 @@ pub struct Encoder<R: Read, W: Write> {
}
impl<R: Read, W: Write> Encoder<R, W> {
/// Creates a new encoder with the given reader and writer. If alphabet is
/// `None` the encoder will use the default rfc4648 alphabet.
pub fn new(reader: R, writer: W, alphabet: Option<B64Alphabet>) -> Self {
Self {
reader,
@ -91,14 +93,7 @@ impl<R: Read, W: Write> Encoder<R, W> {
}
num >>= 6;
}
write!(
self.writer,
"{}{}{}{}",
char::try_from(obuf[0]).unwrap(),
char::try_from(obuf[1]).unwrap(),
char::try_from(obuf[2]).unwrap(),
char::try_from(obuf[3]).unwrap()
)?;
write!(self.writer, "{}{}{}{}", obuf[0], obuf[1], obuf[2], obuf[3])?;
if outlen < 4 {
break;
}

View File

@ -1,10 +1,6 @@
mod decode;
mod encode;
pub use {
decode::{Decoder as B64Decoder, Error as B64DecoderError},
encode::{Encoder as B64Encoder, Error as B64EncoderError},
};
#[warn(clippy::all, clippy::pedantic)]
pub mod decode;
pub mod encode;
#[derive(Clone, Copy)]
pub struct B64Alphabet {
@ -29,7 +25,7 @@ impl Default for B64Alphabet {
}
impl B64Alphabet {
pub fn get(&self, c: char) -> Option<usize> {
pub(crate) fn get(&self, c: char) -> Option<usize> {
for (idx, x) in self.items.iter().enumerate() {
if *x == c {
return Some(idx);
@ -38,7 +34,7 @@ impl B64Alphabet {
None
}
pub fn pad(&self) -> char {
pub(crate) fn pad(&self) -> char {
self.pad
}
}