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
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
/// Provides validated string representation of bit sequence.
///
/// '0' is interpreted as _0_.
/// '1' is interpreted as _1_.
/// '_' is just ignored.
///
/// # Examples
/// ```
/// use succinct_rs::BitString;
///
/// let bs = BitString::new("01");
/// assert_eq!(bs.str(), "01");
///
/// let bs = BitString::new("0111_0101");
/// assert_eq!(bs.str(), "01110101");
/// ```
///
/// # Panics
/// When:
/// - `s` contains any character other than '0', '1', and '_'.
/// - `s` does not contain any '0' or '1'
pub struct BitString {
    s: String,
}

impl BitString {
    /// Constructor.
    pub fn new(s: &str) -> Self {
        let parsed = s
            .chars()
            .filter(|c| match c {
                '0' => true,
                '1' => true,
                '_' => false,
                _ => panic!("`str` must consist of '0' or '1'. '{}' included.", c),
            })
            .collect::<String>();

        assert!(!parsed.is_empty(), "`str` must contain any '0' or '1'.");

        Self {
            s: String::from(parsed),
        }
    }

    /// Getter.
    pub fn str(&self) -> &str {
        &self.s
    }
}

#[cfg(test)]
mod new_success_tests {
    use super::super::BitString;

    macro_rules! parameterized_from_valid_str_tests {
        ($($name:ident: $value:expr,)*) => {
        $(
            #[test]
            fn $name() {
                let (in_s, expected_str) = $value;
                let bvs = BitString::new(in_s);
                assert_eq!(bvs.str(), expected_str);
            }
        )*
        }
    }

    parameterized_from_valid_str_tests! {
        s1: ("0", "0"),
        s2: ("1", "1"),
        s3: ("00", "00"),
        s4: ("01", "01"),
        s5: ("10", "10"),
        s6: ("11", "11"),
        s7_1: ("01010101010111001000001", "01010101010111001000001"),
        s7_2: ("01010101_01011100_1000001", "01010101010111001000001"),
    }
}

#[cfg(test)]
mod new_failure_tests {
    use super::super::BitString;

    macro_rules! parameterized_from_invalid_str_tests {
        ($($name:ident: $value:expr,)*) => {
        $(
            #[test]
            #[should_panic]
            fn $name() {
                let in_s = $value;
                let _ = BitString::new(in_s);
            }
        )*
        }
    }

    parameterized_from_invalid_str_tests! {
        s0: "",
        s1: " ",
        s2: " 0",
        s3: "0 ",
        s4: "1 0",
        s5: "0",
        s6: "1",
        s7: "012",
        s8: "01二",
        s9: "_____",
    }
}