use std::{cmp, ops};
pub const ACT_ONE_LENGTH: usize = 50;
pub const ACT_TWO_LENGTH: usize = 50;
pub const ACT_THREE_LENGTH: usize = 66;
pub const EMPTY_ACT_ONE: ActOne = [0; ACT_ONE_LENGTH];
pub const EMPTY_ACT_TWO: ActTwo = [0; ACT_TWO_LENGTH];
pub const EMPTY_ACT_THREE: ActThree = [0; ACT_THREE_LENGTH];
type ActOne = [u8; ACT_ONE_LENGTH];
type ActTwo = [u8; ACT_TWO_LENGTH];
type ActThree = [u8; ACT_THREE_LENGTH];
#[derive(Copy, Clone, Debug)]
pub enum Act {
One(ActOne),
Two(ActTwo),
Three(ActThree),
}
impl Act {
fn len(&self) -> usize { self.as_ref().len() }
}
impl From<ActBuilder> for Act {
fn from(act_builder: ActBuilder) -> Self {
assert!(act_builder.is_finished());
act_builder.partial_act
}
}
impl ops::Deref for Act {
type Target = [u8];
fn deref(&self) -> &Self::Target {
match self {
Act::One(ref act) => act,
Act::Two(ref act) => act,
Act::Three(ref act) => act,
}
}
}
impl AsRef<[u8]> for Act {
fn as_ref(&self) -> &[u8] { self }
}
#[derive(Debug)]
pub struct ActBuilder {
partial_act: Act,
write_pos: usize,
}
impl ActBuilder {
pub fn new(empty_act: Act) -> Self {
Self {
partial_act: empty_act,
write_pos: 0,
}
}
pub fn fill(&mut self, input: &[u8]) -> usize {
macro_rules! fill_act_content {
($act:expr, $write_pos:expr, $input:expr) => {{
let fill_amount =
cmp::min($act.len() - $write_pos, $input.len());
$act[$write_pos..$write_pos + fill_amount]
.copy_from_slice(&$input[..fill_amount]);
$write_pos += fill_amount;
fill_amount
}};
}
match self.partial_act {
Act::One(ref mut act) => {
fill_act_content!(act, self.write_pos, input)
}
Act::Two(ref mut act) => {
fill_act_content!(act, self.write_pos, input)
}
Act::Three(ref mut act) => {
fill_act_content!(act, self.write_pos, input)
}
}
}
pub fn is_finished(&self) -> bool {
self.write_pos == self.partial_act.len()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn partial_fill() {
let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
let input = [1, 2, 3];
let bytes_read = builder.fill(&input);
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
assert_eq!(builder.write_pos, 3);
assert!(!builder.is_finished());
assert_eq!(bytes_read, input.len());
}
#[test]
fn exact_fill() {
let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
let input = [0; ACT_ONE_LENGTH];
let bytes_read = builder.fill(&input);
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
assert_eq!(builder.write_pos, ACT_ONE_LENGTH);
assert!(builder.is_finished());
assert_eq!(Act::from(builder).as_ref(), &input[..]);
assert_eq!(bytes_read, input.len());
}
#[test]
fn over_fill() {
let mut builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
let input = [0; ACT_ONE_LENGTH + 1];
let bytes_read = builder.fill(&input);
assert_eq!(builder.partial_act.len(), ACT_ONE_LENGTH);
assert_eq!(builder.write_pos, ACT_ONE_LENGTH);
assert!(builder.is_finished());
assert_eq!(Act::from(builder).as_ref(), &input[..ACT_ONE_LENGTH]);
assert_eq!(bytes_read, ACT_ONE_LENGTH);
}
#[test]
#[should_panic(expected = "assertion failed: act_builder.is_finished()")]
fn convert_not_finished_panics() {
let builder = ActBuilder::new(Act::One(EMPTY_ACT_ONE));
let _should_panic = Act::from(builder);
}
}