Created
January 4, 2018 09:17
-
-
Save danneu/2ec3f601183cc9c3ba84bf06d92274df to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Since an Encoder and Decoder live as long as a Codec, I'd | |
// like for them both to share a reference to one instread | |
// of cloning it. | |
// | |
// And do I want refs or slices in this sort of situation? I seem to pick one at random. | |
// EXAMPLE | |
fn main() { | |
let base2 = Codec::new("01".chars().collect()); | |
println!("{:?} {:?}", base2.encode(420), base2.decode(base2.encode(420).as_ref())); | |
let base16 = Codec::new("0123456789abcdef".chars().collect()); | |
println!("{:?} {:?}", base16.encode(420), base16.decode(base16.encode(420).as_ref())); | |
} | |
// PUBLIC | |
pub struct Codec { | |
encoder: Encoder, | |
decoder: Decoder | |
} | |
impl Codec { | |
pub fn new(alphabet: Vec<char>) -> Codec { | |
Codec { | |
encoder: Encoder::new(alphabet.clone()), | |
decoder: Decoder::new(alphabet) | |
} | |
} | |
pub fn encode(&self, x: u64) -> String { | |
self.encoder.encode(x) | |
} | |
pub fn decode(&self, x: &str) -> Option<u64> { | |
self.decoder.decode(x) | |
} | |
} | |
// PRIVATE | |
struct Encoder { | |
alphabet: Vec<char> | |
} | |
impl Encoder { | |
fn new(alphabet: Vec<char>) -> Encoder { Encoder { alphabet } } | |
fn encode(&self, n: u64) -> String { | |
let radix = self.alphabet.len(); | |
let mut n = n; | |
let mut s = String::new(); | |
while n >= radix as u64 { | |
let rem = n % (radix as u64); | |
s.push(self.alphabet[rem as usize]); | |
n = ((n / radix as u64) as i64) as u64; | |
} | |
s.push(self.alphabet[n as usize]); | |
s.chars().rev().collect() | |
} | |
} | |
struct Decoder { | |
alphabet: Vec<char> | |
} | |
impl Decoder { | |
fn new(alphabet: Vec<char>) -> Decoder { Decoder { alphabet } } | |
fn decode(&self, s: &str) -> Option<u64> { | |
let radix = self.alphabet.len(); | |
let mut idxs: Vec<usize> = Vec::with_capacity(s.len()); | |
for a in s.chars() { | |
match self.alphabet.iter().position(|&b: &char| a == b) { | |
None => return None, | |
Some(idx) => idxs.push(idx) | |
} | |
} | |
return Some(idxs | |
.into_iter() | |
.rev() // TODO: RevVec | |
.enumerate() | |
.map(|(power, n): (usize, usize)| { | |
(n as u64 * ((radix as f64).powi(power as i32) as u64)) | |
}) | |
.sum()) | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment