Initial commit

This commit is contained in:
Nathan Fisher 2025-01-22 12:16:36 -05:00
commit 3ab6634661
5 changed files with 194 additions and 0 deletions

1
.gitignore vendored Normal file
View file

@ -0,0 +1 @@
/target

7
Cargo.lock generated Normal file
View file

@ -0,0 +1,7 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "b2"
version = "0.1.0"

6
Cargo.toml Normal file
View file

@ -0,0 +1,6 @@
[package]
name = "b2"
version = "0.1.0"
edition = "2021"
[dependencies]

176
src/encode.rs Normal file
View file

@ -0,0 +1,176 @@
use std::io::{self, ErrorKind, Read, Write};
#[derive(Default, Clone, Copy)]
pub enum Style {
#[default]
Plain,
Spaces,
Prefixed,
Table,
}
pub struct Encoder<R: Read, W: Write> {
reader: R,
writer: W,
style: Style,
wrap: Option<usize>,
}
impl<R: Read, W: Write> Encoder<R, W> {
pub fn new(reader: R, writer: W, style: Option<Style>, mut wrap: Option<usize>) -> Self {
let style = style.unwrap_or_default();
if let Style::Table = style {
wrap = match wrap {
Some(u) => Some(u),
None => Some(5),
};
}
Self {
reader,
writer,
style,
wrap,
}
}
pub fn encode(mut self) -> Result<W, io::Error> {
let mut bytes = self.reader.bytes();
let mut total = 0;
loop {
match bytes.next() {
Some(Ok(b)) => match self.style {
Style::Plain => {
if let Some(w) = self.wrap {
if total > 0 && total % w == 0 {
writeln!(self.writer)?;
}
}
write!(self.writer, "{b:08b}")?;
}
Style::Spaces => {
if let Some(w) = self.wrap {
if total > 0 && total % w == 0 {
writeln!(self.writer)?;
} else {
write!(self.writer, " ")?;
}
} else if total > 0 {
write!(self.writer, " ")?;
}
write!(self.writer, "{b:08b}")?;
}
Style::Prefixed => {
if let Some(w) = self.wrap {
if total > 0 && total % w == 0 {
writeln!(self.writer)?;
} else if total > 0 {
write!(self.writer, " ")?;
}
} else if total > 0 {
write!(self.writer, " ")?;
}
write!(self.writer, "{b:#010b}")?;
}
Style::Table => {
if let Some(w) = self.wrap {
if total % w == 0 {
if total > 0 {
write!(self.writer, "\n{total:>5}\t{b:#010b}")?;
} else {
write!(self.writer, "{total:>5}\t{b:#010b}")?;
}
} else {
write!(self.writer, " {b:#010b}")?;
}
} else {
unreachable!();
}
}
},
Some(Err(e)) if e.kind() == ErrorKind::UnexpectedEof => break,
Some(Err(e)) if e.kind() == ErrorKind::Interrupted => continue,
Some(Err(e)) => return Err(e),
None => break,
}
total += 1;
}
if let Some(w) = self.wrap {
if total % w != 0 {
writeln!(self.writer)?;
}
} else {
writeln!(self.writer)?;
}
Ok(self.writer)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn hello_plain() {
let encoder = Encoder::new("Hello, World!".as_bytes(), vec![], None, None);
assert_eq!(
encoder.encode().unwrap(),
b"01001000011001010110110001101100011011110010110000100000010101110110111101110010011011000110010000100001\n"
);
}
#[test]
fn hello_spaced() {
let encoder = Encoder::new(
"Hello, World!".as_bytes(),
vec![],
Some(Style::Spaces),
None,
);
assert_eq!(
encoder.encode().unwrap(),
b"01001000 01100101 01101100 01101100 01101111 00101100 00100000 01010111 01101111 01110010 01101100 01100100 00100001\n"
);
}
#[test]
fn hello_prefixed() {
let encoder = Encoder::new(
"Hello, World!".as_bytes(),
vec![],
Some(Style::Prefixed),
None,
);
assert_eq!(
encoder.encode().unwrap(),
b"0b01001000 0b01100101 0b01101100 0b01101100 0b01101111 0b00101100 0b00100000 0b01010111 0b01101111 0b01110010 0b01101100 0b01100100 0b00100001\n"
);
}
#[test]
fn hello_prefixed_wrapped() {
let encoder = Encoder::new(
"Hello, World!".as_bytes(),
vec![],
Some(Style::Prefixed),
Some(4),
);
assert_eq!(
encoder.encode().unwrap(),
b"0b01001000 0b01100101 0b01101100 0b01101100\n0b01101111 0b00101100 0b00100000 0b01010111\n0b01101111 0b01110010 0b01101100 0b01100100\n0b00100001\n"
);
}
#[test]
fn hello_table() {
let encoder = Encoder::new(
"Hello, World!".as_bytes(),
vec![],
Some(Style::Table),
Some(4),
);
assert_eq!(
encoder.encode().unwrap(),
b" 0\t0b01001000 0b01100101 0b01101100 0b01101100\n 4\t0b01101111 0b00101100 0b00100000 0b01010111\n 8\t0b01101111 0b01110010 0b01101100 0b01100100\n 12\t0b00100001\n"
);
}
}

4
src/lib.rs Normal file
View file

@ -0,0 +1,4 @@
#![warn(clippy::all, clippy::pedantic)]
mod encode;
pub use encode::{Encoder, Style};