Skip to content

Instantly share code, notes, and snippets.

@fancellu
Created February 8, 2024 22:24
Show Gist options
  • Save fancellu/c16c7a43cc47be4426a7938aa101dd3f to your computer and use it in GitHub Desktop.
Save fancellu/c16c7a43cc47be4426a7938aa101dd3f to your computer and use it in GitHub Desktop.
Rust run length encoding
use std::fmt::Display;
use std::str::FromStr;
#[derive(Debug)]
struct Rle {
data: Vec<u8>,
}
impl Rle {
fn decode(&self) -> String {
let mut s = String::new();
for i in 0..self.data.len() {
if i % 2 == 0 {
let count = self.data[i] as usize;
for _ in 0..count {
s.push(self.data[i + 1] as char);
}
}
}
s
}
}
impl Into<String> for Rle {
fn into(self) -> String {
self.decode()
}
}
fn dump(count: &mut u8, c: char, data: &mut Vec<u8>) {
while count > &mut 9 {
data.push(9);
data.push(c as u8);
*count -= 9;
}
data.push(*count);
data.push(c as u8);
}
impl FromStr for Rle {
type Err = ();
fn from_str(s: &str) -> Result<Self, Self::Err> {
if s.is_empty() {
return Ok(Rle { data: vec![] });
}
let mut data = Vec::new();
let mut iter = s.chars();
let mut c = iter.next().unwrap();
let mut count = 1;
for next in iter {
if next == c {
count += 1;
} else {
dump(&mut count, c, &mut data);
count = 1;
c = next;
}
}
// need to handle last run
dump(&mut count, c, &mut data);
Ok(Rle { data })
}
}
impl From<&str> for Rle {
fn from(s: &str) -> Self {
Rle::from_str(&s).unwrap()
}
}
impl Display for Rle {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let mut s = String::new();
for i in 0..self.data.len() {
if i % 2 == 0 {
s.push_str(&self.data[i].to_string());
} else {
s.push(self.data[i] as char);
}
}
write!(f, "{}", s)
}
}
fn main() {
println!("---normal---");
let input = "AAAABBBCCXYZDDDDEEEFFFAAAAAABBBBBBBBBBBBBBBBBBBBBBBB";
let rle = Rle::from(input);
println!("{:?}", rle.data);
println!("{}", rle);
// I could have just called rle.decode()
let output: String = rle.into();
assert_eq!(output, input);
println!("{}", output);
println!("---blank---");
let input = "";
let rle = Rle::from_str(input).unwrap();
println!("{:?}", rle.data);
println!("{}", rle);
let output: String = rle.into();
assert_eq!(output, input);
println!("{}", output);
}
@fancellu
Copy link
Author

fancellu commented Feb 8, 2024

Output

---normal---
[4, 65, 3, 66, 2, 67, 1, 88, 1, 89, 1, 90, 4, 68, 3, 69, 3, 70, 6, 65, 9, 66, 9, 66, 6, 66]
4A3B2C1X1Y1Z4D3E3F6A9B9B6B
AAAABBBCCXYZDDDDEEEFFFAAAAAABBBBBBBBBBBBBBBBBBBBBBBB
---blank---
[]

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment