1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
//! # Description
//!
//! This method uses the trailing [ASCII_WHITESPACE] to encode bits.
//! If the whitespace is present the bit 1 is encoded, otherwise 0.
//!
//! This method provides both encoding and decoding algorithm.

use std::error::Error;

use log::{trace};

use crate::{binary::{Bit}, context::{Context, ContextError}, decoder::Decoder, encoder::{Capacity, Encoder, EncoderResult}};

/// Character used as the trailing whitespace in the method.
pub const ASCII_WHITESPACE: char = ' ';

use super::Method;
// Unit structure used to define the method.
// Implements both [Encoder](crate::encoder::Encode) and [Decoder](crate::decoder::Decoder) traits.
// Accepts any [Context](crate::context::Context).
pub struct TrailingWhitespaceMethod;

impl Default for TrailingWhitespaceMethod {
    fn default() -> Self {
        Self::new()
    }
}

impl TrailingWhitespaceMethod {
    pub fn new() -> Self {
        TrailingWhitespaceMethod {}
    }
}

impl Capacity for TrailingWhitespaceMethod {
    fn bitrate(&self) -> usize {
        1
    }
}

impl<E> Encoder<E> for TrailingWhitespaceMethod
where
    E: Context,
{
    fn partial_encode(
        &self,
        context: &mut E,
        data: &mut dyn Iterator<Item = Bit>,
    ) -> Result<EncoderResult, Box<dyn Error>> {
        Ok(match data.next() {
            Some(Bit(1)) => {
                trace!("Putting whitespace at the end of the line");
                context.get_current_text_mut()?.push(ASCII_WHITESPACE);
                EncoderResult::Success
            }
            None => EncoderResult::NoDataLeft,
            _ => {
                trace!("Skipping trailing whitespace");
                EncoderResult::Success
            }
        })
    }
}

impl<D> Decoder<D> for TrailingWhitespaceMethod
where
    D: Context,
{
    fn partial_decode(&self, context: &D) -> Result<Vec<Bit>, ContextError> {
        let bit = if context.get_current_text()?.ends_with(ASCII_WHITESPACE) {
            trace!("Found trailing whitespace");
            Bit(1)
        } else {
            trace!("No trailing whitespace");
            Bit(0)
        };
        Ok(vec![bit])
    }
}

impl<E, D> Method<E, D> for TrailingWhitespaceMethod
where
    E: Context,
    D: Context,
{
}