Initial commit
This commit is contained in:
commit
683aa50d2a
6 changed files with 178 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
target/
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "b64"
|
||||
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "b64"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
36
src/decode.rs
Normal file
36
src/decode.rs
Normal file
|
@ -0,0 +1,36 @@
|
|||
pub use {
|
||||
super::B64Alphabet,
|
||||
std::{
|
||||
io::{self, Read, Write, ErrorKind},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Io(io::Error),
|
||||
IllegalChar(char),
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<char> for Error {
|
||||
fn from(value: char) -> Self {
|
||||
Self::IllegalChar(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Decoder<R: Read, W: Write> {
|
||||
reader: R,
|
||||
writer: W,
|
||||
alphabet: B64Alphabet,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
}
|
||||
|
81
src/encode.rs
Normal file
81
src/encode.rs
Normal file
|
@ -0,0 +1,81 @@
|
|||
pub use {
|
||||
super::B64Alphabet,
|
||||
std::{
|
||||
fmt::{self, Write},
|
||||
io::{self, Read, ErrorKind},
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {
|
||||
Io(io::Error),
|
||||
Fmt(fmt::Error),
|
||||
}
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::Io(e) => write!(f, "{e}"),
|
||||
Self::Fmt(e) => write!(f, "{e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<io::Error> for Error {
|
||||
fn from(value: io::Error) -> Self {
|
||||
Self::Io(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<fmt::Error> for Error {
|
||||
fn from(value: fmt::Error) -> Self {
|
||||
Self::Fmt(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for Error {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::Fmt(e) => Some(e),
|
||||
Self::Io(e) => Some(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Encoder<R: Read, W: Write> {
|
||||
reader: R,
|
||||
writer: W,
|
||||
alphabet: B64Alphabet,
|
||||
}
|
||||
|
||||
impl<R: Read, W: Write> Encoder<R, W> {
|
||||
pub fn new(reader: R, writer: W, alphabet: B64Alphabet) -> Self {
|
||||
Self { reader, writer, alphabet }
|
||||
}
|
||||
|
||||
pub fn encode(&mut self) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl<R: Read> Encoder<R, String> {
|
||||
pub fn output(self) -> String {
|
||||
self.writer
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn encode() {
|
||||
let mut encoder = Encoder {
|
||||
reader: "Hello, World!".as_bytes(),
|
||||
writer: String::new(),
|
||||
alphabet: B64Alphabet::default(),
|
||||
};
|
||||
encoder.encode().unwrap();
|
||||
assert_eq!(encoder.output(), "SGVsbG8sIFdvcmxkIQ==");
|
||||
}
|
||||
}
|
45
src/lib.rs
Normal file
45
src/lib.rs
Normal file
|
@ -0,0 +1,45 @@
|
|||
mod encode;
|
||||
mod decode;
|
||||
|
||||
pub use {
|
||||
encode::{Error as B64EncoderError, Encoder as B64Encoder},
|
||||
decode::{Error as B64DecoderError, Decoder as B64Decoder},
|
||||
};
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct B64Alphabet {
|
||||
items: [char; 64],
|
||||
pad: char,
|
||||
}
|
||||
|
||||
pub static B64_RFC4648_ALPHABET: B64Alphabet = B64Alphabet {
|
||||
items: [
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
|
||||
'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd',
|
||||
'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's',
|
||||
't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7',
|
||||
'8', '9', '+', '/',
|
||||
],
|
||||
pad: '=',
|
||||
};
|
||||
|
||||
impl Default for B64Alphabet {
|
||||
fn default() -> Self {
|
||||
B64_RFC4648_ALPHABET
|
||||
}
|
||||
}
|
||||
|
||||
impl B64Alphabet {
|
||||
pub fn idx(&self, c: char) -> Option<usize> {
|
||||
for (idx, x) in self.items.iter().enumerate() {
|
||||
if *x == c {
|
||||
return Some(idx)
|
||||
}
|
||||
};
|
||||
None
|
||||
}
|
||||
|
||||
pub fn pad(&self) -> char {
|
||||
self.pad
|
||||
}
|
||||
}
|
Loading…
Add table
Reference in a new issue