Begin getting docs in order
This commit is contained in:
parent
d203aaf5d3
commit
13fda08e1b
@ -1,13 +1,30 @@
|
|||||||
pub use {
|
use {
|
||||||
super::B64Alphabet,
|
super::B64Alphabet,
|
||||||
std::io::{self, ErrorKind, Read, Write},
|
std::{
|
||||||
|
fmt,
|
||||||
|
io::{self, ErrorKind, Read, Write},
|
||||||
|
num::TryFromIntError,
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
|
/// Errors which might possibly occur while decoding base64 encoded data
|
||||||
pub enum Error {
|
pub enum Error {
|
||||||
Io(io::Error),
|
Io(io::Error),
|
||||||
IllegalChar(char),
|
IllegalChar(char),
|
||||||
MissingPadding,
|
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 {
|
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> {
|
pub struct Decoder<R: Read, W: Write> {
|
||||||
reader: R,
|
reader: R,
|
||||||
writer: W,
|
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> {
|
pub fn decode(&mut self) -> Result<(), Error> {
|
||||||
loop {
|
loop {
|
||||||
let mut ibuf = [0_u8; 4];
|
let mut in_buf = [0_u8; 4];
|
||||||
let mut obuf = [0_u8; 3];
|
let mut out_buf = [0_u8; 3];
|
||||||
let mut num = 0_u32;
|
let mut num = 0_u32;
|
||||||
let mut n_bytes = 0;
|
let mut n_bytes = 0;
|
||||||
loop {
|
loop {
|
||||||
n_bytes += match self.reader.read(&mut ibuf) {
|
n_bytes += match self.reader.read(&mut in_buf) {
|
||||||
Ok(n) => n,
|
Ok(n) => n,
|
||||||
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
Err(e) if e.kind() == ErrorKind::Interrupted => continue,
|
||||||
Err(e) => return Err(e.into()),
|
Err(e) => return Err(e.into()),
|
||||||
@ -57,7 +100,7 @@ impl<R: Read, W: Write> Decoder<R, W> {
|
|||||||
_ => return Err(Error::MissingPadding),
|
_ => return Err(Error::MissingPadding),
|
||||||
}
|
}
|
||||||
let mut bytes = 0;
|
let mut bytes = 0;
|
||||||
for (i, &c) in ibuf.iter().enumerate() {
|
for (i, &c) in in_buf.iter().enumerate() {
|
||||||
let c = c.into();
|
let c = c.into();
|
||||||
num <<= 6;
|
num <<= 6;
|
||||||
if c == self.alphabet.pad() {
|
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 {
|
let Some(idx) = self.alphabet.get(c) else {
|
||||||
return Err(Error::IllegalChar(c));
|
return Err(Error::IllegalChar(c));
|
||||||
};
|
};
|
||||||
num |= idx as u32;
|
num |= u32::try_from(idx)?;
|
||||||
bytes += 1;
|
bytes += 1;
|
||||||
}
|
}
|
||||||
let olen = bytes * 6 / 8;
|
let olen = bytes * 6 / 8;
|
||||||
for i in (0..3).rev() {
|
for i in (0..3).rev() {
|
||||||
obuf[i] = (num & 0xff) as u8;
|
out_buf[i] = (num & 0xff) as u8;
|
||||||
num >>= 8;
|
num >>= 8;
|
||||||
}
|
}
|
||||||
self.writer.write_all(&mut obuf[0..olen])?;
|
self.writer.write_all(&out_buf[0..olen])?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
pub use {
|
use {
|
||||||
super::B64Alphabet,
|
super::B64Alphabet,
|
||||||
std::{
|
std::{
|
||||||
fmt::{self, Write},
|
fmt::{self, Write},
|
||||||
@ -49,6 +49,8 @@ pub struct Encoder<R: Read, W: Write> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Read, W: Write> Encoder<R, W> {
|
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 {
|
pub fn new(reader: R, writer: W, alphabet: Option<B64Alphabet>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
reader,
|
reader,
|
||||||
@ -91,14 +93,7 @@ impl<R: Read, W: Write> Encoder<R, W> {
|
|||||||
}
|
}
|
||||||
num >>= 6;
|
num >>= 6;
|
||||||
}
|
}
|
||||||
write!(
|
write!(self.writer, "{}{}{}{}", obuf[0], obuf[1], obuf[2], obuf[3])?;
|
||||||
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()
|
|
||||||
)?;
|
|
||||||
if outlen < 4 {
|
if outlen < 4 {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
14
src/lib.rs
14
src/lib.rs
@ -1,10 +1,6 @@
|
|||||||
mod decode;
|
#[warn(clippy::all, clippy::pedantic)]
|
||||||
mod encode;
|
pub mod decode;
|
||||||
|
pub mod encode;
|
||||||
pub use {
|
|
||||||
decode::{Decoder as B64Decoder, Error as B64DecoderError},
|
|
||||||
encode::{Encoder as B64Encoder, Error as B64EncoderError},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Clone, Copy)]
|
#[derive(Clone, Copy)]
|
||||||
pub struct B64Alphabet {
|
pub struct B64Alphabet {
|
||||||
@ -29,7 +25,7 @@ impl Default for B64Alphabet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl 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() {
|
for (idx, x) in self.items.iter().enumerate() {
|
||||||
if *x == c {
|
if *x == c {
|
||||||
return Some(idx);
|
return Some(idx);
|
||||||
@ -38,7 +34,7 @@ impl B64Alphabet {
|
|||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn pad(&self) -> char {
|
pub(crate) fn pad(&self) -> char {
|
||||||
self.pad
|
self.pad
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user