Skip to main content

libsurfer/translation/
basic_translators.rs

1use super::{TranslationPreference, ValueKind, VariableInfo};
2use crate::wave_container::{ScopeId, VarId, VariableMeta};
3
4use eyre::Result;
5use itertools::Itertools;
6use num::{One, Zero};
7use surfer_translation_types::{
8    BasicTranslator, VariableValue, check_vector_variable, extend_string,
9    kind_for_binary_representation, parse_value_to_numeric,
10};
11
12/// Splits a string into groups of `n` characters.
13/// If the string length is not divisible by `n`, the first group will be shorter.
14/// The string must only consist of ASCII characters.
15#[must_use]
16pub fn group_n_chars(s: &str, n: usize) -> Vec<&str> {
17    let mut groups = Vec::new();
18    let len = s.len();
19    let rem = len % n;
20    let mut start = 0;
21    if rem > 0 {
22        groups.push(&s[0..rem]);
23        start = rem;
24    }
25    while start < len {
26        let end = (start + n).min(len);
27        groups.push(&s[start..end]);
28        start += n;
29    }
30    groups
31}
32
33/// Map to radix-based representation, in practice hex or octal
34fn map_to_radix(s: &str, radix: usize, num_bits: u32) -> (String, ValueKind) {
35    let mut had_invalid_digit = false;
36    let formatted = group_n_chars(
37        &format!("{extra_bits}{s}", extra_bits = extend_string(s, num_bits)),
38        radix,
39    )
40    .into_iter()
41    .map(|g| match g {
42        g if g.contains('x') => "x".to_string(),
43        g if g.contains('z') => "z".to_string(),
44        g if g.contains('-') => "-".to_string(),
45        g if g.contains('u') => "u".to_string(),
46        g if g.contains('w') => "w".to_string(),
47        g if g.contains('h') => "h".to_string(),
48        g if g.contains('l') => "l".to_string(),
49        g => {
50            if let Ok(val) = u8::from_str_radix(g, 2) {
51                format!("{val:x}")
52            } else {
53                had_invalid_digit = true;
54                "?".to_string()
55            }
56        }
57    })
58    .join("");
59
60    let kind = if had_invalid_digit {
61        ValueKind::Error
62    } else {
63        kind_for_binary_representation(&formatted)
64    };
65    (formatted, kind)
66}
67
68fn check_wordlength(
69    num_bits: Option<u32>,
70    required: impl FnOnce(u32) -> bool,
71) -> Result<TranslationPreference> {
72    if let Some(num_bits) = num_bits {
73        if required(num_bits) {
74            Ok(TranslationPreference::Yes)
75        } else {
76            Ok(TranslationPreference::No)
77        }
78    } else {
79        Ok(TranslationPreference::No)
80    }
81}
82
83pub struct HexTranslator {}
84
85impl BasicTranslator<VarId, ScopeId> for HexTranslator {
86    fn name(&self) -> String {
87        String::from("Hexadecimal")
88    }
89
90    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
91        match value {
92            VariableValue::BigUint(v) => (
93                format!("{v:0width$x}", width = num_bits.div_ceil(4) as usize),
94                ValueKind::Normal,
95            ),
96            VariableValue::String(s) => map_to_radix(s, 4, num_bits),
97        }
98    }
99}
100
101pub struct BitTranslator {}
102
103impl BasicTranslator<VarId, ScopeId> for BitTranslator {
104    fn name(&self) -> String {
105        String::from("Bit")
106    }
107
108    fn basic_translate(&self, _num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
109        match value {
110            VariableValue::BigUint(v) => (
111                if (*v).is_zero() {
112                    "0".to_string()
113                } else if (*v).is_one() {
114                    "1".to_string()
115                } else {
116                    "-".to_string()
117                },
118                ValueKind::Normal,
119            ),
120            VariableValue::String(s) => (s.to_string(), kind_for_binary_representation(s)),
121        }
122    }
123
124    fn translates(&self, variable: &VariableMeta) -> Result<TranslationPreference> {
125        if let Some(num_bits) = variable.num_bits {
126            if num_bits == 1u32 {
127                Ok(TranslationPreference::Prefer)
128            } else {
129                Ok(TranslationPreference::No)
130            }
131        } else {
132            Ok(TranslationPreference::No)
133        }
134    }
135
136    fn variable_info(&self, _variable: &VariableMeta) -> Result<VariableInfo> {
137        Ok(VariableInfo::Bool)
138    }
139}
140
141pub struct OctalTranslator {}
142
143impl BasicTranslator<VarId, ScopeId> for OctalTranslator {
144    fn name(&self) -> String {
145        String::from("Octal")
146    }
147
148    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
149        match value {
150            VariableValue::BigUint(v) => (
151                format!("{v:0width$o}", width = num_bits.div_ceil(3) as usize),
152                ValueKind::Normal,
153            ),
154            VariableValue::String(s) => map_to_radix(s, 3, num_bits),
155        }
156    }
157}
158
159pub struct GroupingBinaryTranslator {}
160
161impl BasicTranslator<VarId, ScopeId> for GroupingBinaryTranslator {
162    fn name(&self) -> String {
163        String::from("Binary (with groups)")
164    }
165
166    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
167        let (val, color) = match value {
168            VariableValue::BigUint(v) => (
169                format!("{v:0width$b}", width = num_bits as usize),
170                ValueKind::Normal,
171            ),
172            VariableValue::String(s) => (
173                format!("{extra_bits}{s}", extra_bits = extend_string(s, num_bits)),
174                kind_for_binary_representation(s),
175            ),
176        };
177
178        (group_n_chars(&val, 4).join(" "), color)
179    }
180}
181
182pub struct BinaryTranslator {}
183
184impl BasicTranslator<VarId, ScopeId> for BinaryTranslator {
185    fn name(&self) -> String {
186        String::from("Binary")
187    }
188
189    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
190        match value {
191            VariableValue::BigUint(v) => (
192                format!("{v:0width$b}", width = num_bits as usize),
193                ValueKind::Normal,
194            ),
195            VariableValue::String(s) => (
196                format!("{extra_bits}{s}", extra_bits = extend_string(s, num_bits)),
197                kind_for_binary_representation(s),
198            ),
199        }
200    }
201}
202
203pub struct ASCIITranslator {}
204
205impl BasicTranslator<VarId, ScopeId> for ASCIITranslator {
206    fn name(&self) -> String {
207        String::from("ASCII")
208    }
209
210    fn basic_translate(&self, _num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
211        match value {
212            VariableValue::BigUint(v) => (
213                v.to_bytes_be()
214                    .into_iter()
215                    .map(|val| (val as char).to_string())
216                    .join(""),
217                ValueKind::Normal,
218            ),
219            VariableValue::String(s) => match check_vector_variable(s) {
220                Some(v) => v,
221                None => (
222                    group_n_chars(s, 8)
223                        .into_iter()
224                        .map(|substr| {
225                            format!(
226                                "{cval}",
227                                cval = u8::from_str_radix(substr, 2).unwrap_or_else(|_| panic!(
228                                    "Found non-binary digit {substr} in value"
229                                )) as char
230                            )
231                        })
232                        .join(""),
233                    ValueKind::Normal,
234                ),
235            },
236        }
237    }
238}
239
240fn decode_lebxxx(value: &num::BigUint) -> Result<num::BigUint, &'static str> {
241    let bytes = value.to_bytes_be();
242    match bytes.first() {
243        Some(b) if b & 0x80 != 0 => return Err("invalid MSB"),
244        _ => (),
245    }
246
247    let first: num::BigUint = bytes.first().copied().unwrap_or(0).into();
248    bytes.iter().skip(1).try_fold(first, |result, b| {
249        if (b & 0x80 == 0) == (result.is_zero()) {
250            Ok((result << 7) + (*b & 0x7f))
251        } else {
252            Err("invalid flag")
253        }
254    })
255}
256
257pub struct LebTranslator {}
258
259impl BasicTranslator<VarId, ScopeId> for LebTranslator {
260    fn name(&self) -> String {
261        "LEBxxx".to_string()
262    }
263
264    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
265        let decoded = match value {
266            VariableValue::BigUint(v) => decode_lebxxx(v),
267            VariableValue::String(s) => match check_vector_variable(s) {
268                Some(v) => return v,
269                None => match num::BigUint::parse_bytes(s.as_bytes(), 2) {
270                    Some(bi) => decode_lebxxx(&bi),
271                    None => return ("INVALID".to_owned(), ValueKind::Warn),
272                },
273            },
274        };
275
276        match decoded {
277            Ok(decoded) => (decoded.to_str_radix(10), ValueKind::Normal),
278            Err(s) => (
279                s.to_owned()
280                    + ": "
281                    + &GroupingBinaryTranslator {}
282                        .basic_translate(num_bits, value)
283                        .0,
284                ValueKind::Warn,
285            ),
286        }
287    }
288
289    fn translates(&self, variable: &VariableMeta) -> Result<TranslationPreference> {
290        check_wordlength(variable.num_bits, |n| (n.is_multiple_of(8)) && n > 0)
291    }
292}
293
294pub struct NumberOfOnesTranslator {}
295
296impl BasicTranslator<VarId, ScopeId> for NumberOfOnesTranslator {
297    fn name(&self) -> String {
298        String::from("Number of ones")
299    }
300
301    fn basic_translate(&self, _num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
302        match value {
303            VariableValue::BigUint(v) => (v.count_ones().to_string(), ValueKind::Normal),
304            VariableValue::String(s) => (
305                s.bytes().filter(|b| *b == b'1').count().to_string(),
306                kind_for_binary_representation(s),
307            ),
308        }
309    }
310
311    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
312        Some(parse_value_to_numeric(value, |v| v.count_ones() as f64))
313    }
314}
315
316pub struct TrailingOnesTranslator {}
317
318impl BasicTranslator<VarId, ScopeId> for TrailingOnesTranslator {
319    fn name(&self) -> String {
320        String::from("Trailing ones")
321    }
322
323    fn basic_translate(&self, _num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
324        match value {
325            VariableValue::BigUint(v) => (v.trailing_ones().to_string(), ValueKind::Normal),
326            VariableValue::String(s) => (
327                s.bytes()
328                    .rev()
329                    .take_while(|b| *b == b'1')
330                    .count()
331                    .to_string(),
332                kind_for_binary_representation(s),
333            ),
334        }
335    }
336
337    fn basic_translate_numeric(&self, _num_bits: u32, value: &VariableValue) -> Option<f64> {
338        Some(parse_value_to_numeric(value, |v| v.trailing_ones() as f64))
339    }
340}
341
342pub struct TrailingZerosTranslator {}
343
344impl BasicTranslator<VarId, ScopeId> for TrailingZerosTranslator {
345    fn name(&self) -> String {
346        String::from("Trailing zeros")
347    }
348
349    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
350        match value {
351            VariableValue::BigUint(v) => (
352                v.trailing_zeros()
353                    .unwrap_or(u64::from(num_bits))
354                    .to_string(),
355                ValueKind::Normal,
356            ),
357            VariableValue::String(s) => (
358                (extend_string(s, num_bits) + s)
359                    .bytes()
360                    .rev()
361                    .take_while(|b| *b == b'0')
362                    .count()
363                    .to_string(),
364                kind_for_binary_representation(s),
365            ),
366        }
367    }
368
369    fn basic_translate_numeric(&self, num_bits: u32, value: &VariableValue) -> Option<f64> {
370        Some(parse_value_to_numeric(value, |v| {
371            v.trailing_zeros().unwrap_or(u64::from(num_bits)) as f64
372        }))
373    }
374}
375
376pub struct LeadingOnesTranslator {}
377
378impl BasicTranslator<VarId, ScopeId> for LeadingOnesTranslator {
379    fn name(&self) -> String {
380        String::from("Leading ones")
381    }
382
383    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
384        match value {
385            VariableValue::BigUint(v) => {
386                let s = format!("{v:0width$b}", width = num_bits as usize);
387                self.basic_translate(num_bits, &VariableValue::String(s))
388            }
389            VariableValue::String(s) => (
390                if s.len() == (num_bits as usize) {
391                    s.bytes().take_while(|b| *b == b'1').count().to_string()
392                } else {
393                    "0".to_string()
394                },
395                kind_for_binary_representation(s),
396            ),
397        }
398    }
399
400    fn basic_translate_numeric(&self, num_bits: u32, value: &VariableValue) -> Option<f64> {
401        Some(parse_value_to_numeric(value, |v| {
402            leading_ones(v, u64::from(num_bits)) as f64
403        }))
404    }
405}
406
407pub struct LeadingZerosTranslator {}
408
409impl BasicTranslator<VarId, ScopeId> for LeadingZerosTranslator {
410    fn name(&self) -> String {
411        String::from("Leading zeros")
412    }
413
414    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
415        match value {
416            VariableValue::BigUint(v) => {
417                let s = format!("{v:0width$b}", width = num_bits as usize);
418                self.basic_translate(num_bits, &VariableValue::String(s))
419            }
420            VariableValue::String(s) => (
421                (extend_string(s, num_bits) + s)
422                    .bytes()
423                    .take_while(|b| *b == b'0')
424                    .count()
425                    .to_string(),
426                kind_for_binary_representation(s),
427            ),
428        }
429    }
430
431    fn basic_translate_numeric(&self, num_bits: u32, value: &VariableValue) -> Option<f64> {
432        Some(parse_value_to_numeric(value, |v| {
433            u64::from(num_bits).saturating_sub(v.bits()) as f64
434        }))
435    }
436}
437
438/// Counts leading ones in a `BigUint` value with a given bit width.
439/// Returns 0 if the value has leading zeros (i.e., `v.bits() < num_bits`).
440fn leading_ones(v: &num::BigUint, num_bits: u64) -> u64 {
441    if v.bits() < num_bits {
442        0
443    } else {
444        let mask = (num::BigUint::one() << num_bits) - 1u32;
445        num_bits.saturating_sub((mask ^ v).bits())
446    }
447}
448
449pub struct IdenticalMSBsTranslator {}
450
451impl BasicTranslator<VarId, ScopeId> for IdenticalMSBsTranslator {
452    fn name(&self) -> String {
453        String::from("Identical MSBs")
454    }
455
456    fn basic_translate(&self, num_bits: u32, value: &VariableValue) -> (String, ValueKind) {
457        match value {
458            VariableValue::BigUint(v) => {
459                let s = format!("{v:0width$b}", width = num_bits as usize);
460                self.basic_translate(num_bits, &VariableValue::String(s))
461            }
462            VariableValue::String(s) => {
463                let extended_string = extend_string(s, num_bits) + s;
464                let zeros = extended_string.bytes().take_while(|b| *b == b'0').count();
465                let ones = extended_string.bytes().take_while(|b| *b == b'1').count();
466                let count = ones.max(zeros);
467                (count.to_string(), kind_for_binary_representation(s))
468            }
469        }
470    }
471
472    fn basic_translate_numeric(&self, num_bits: u32, value: &VariableValue) -> Option<f64> {
473        Some(parse_value_to_numeric(value, |v| {
474            let num_bits = u64::from(num_bits);
475            let lz = num_bits.saturating_sub(v.bits());
476            let lo = leading_ones(v, num_bits);
477            lz.max(lo) as f64
478        }))
479    }
480}
481
482#[cfg(test)]
483mod test {
484
485    use num::BigUint;
486
487    use super::*;
488
489    #[test]
490    fn hexadecimal_translation_groups_digits_correctly_string() {
491        assert_eq!(
492            HexTranslator {}
493                .basic_translate(5, &VariableValue::String("10000".to_string()))
494                .0,
495            "10"
496        );
497
498        assert_eq!(
499            HexTranslator {}
500                .basic_translate(5, &VariableValue::String("1000".to_string()))
501                .0,
502            "08"
503        );
504
505        assert_eq!(
506            HexTranslator {}
507                .basic_translate(5, &VariableValue::String("100000".to_string()))
508                .0,
509            "20"
510        );
511        assert_eq!(
512            HexTranslator {}
513                .basic_translate(10, &VariableValue::String("1z00x0".to_string()))
514                .0,
515            "0zx"
516        );
517        assert_eq!(
518            HexTranslator {}
519                .basic_translate(10, &VariableValue::String("z0110".to_string()))
520                .0,
521            "zz6"
522        );
523        assert_eq!(
524            HexTranslator {}
525                .basic_translate(24, &VariableValue::String("xz0110".to_string()))
526                .0,
527            "xxxxx6"
528        );
529    }
530
531    #[test]
532    fn hexadecimal_translation_groups_digits_correctly_bigint() {
533        assert_eq!(
534            HexTranslator {}
535                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b10000u32)))
536                .0,
537            "10"
538        );
539        assert_eq!(
540            HexTranslator {}
541                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b1000u32)))
542                .0,
543            "08"
544        );
545        assert_eq!(
546            HexTranslator {}
547                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0u32)))
548                .0,
549            "00"
550        );
551    }
552
553    #[test]
554    fn octal_translation_groups_digits_correctly_string() {
555        assert_eq!(
556            OctalTranslator {}
557                .basic_translate(5, &VariableValue::String("10000".to_string()))
558                .0,
559            "20"
560        );
561        assert_eq!(
562            OctalTranslator {}
563                .basic_translate(5, &VariableValue::String("100".to_string()))
564                .0,
565            "04"
566        );
567        assert_eq!(
568            OctalTranslator {}
569                .basic_translate(9, &VariableValue::String("x100".to_string()))
570                .0,
571            "xx4"
572        );
573    }
574
575    #[test]
576    fn octal_translation_groups_digits_correctly_bigint() {
577        assert_eq!(
578            OctalTranslator {}
579                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b10000u32)))
580                .0,
581            "20"
582        );
583        assert_eq!(
584            OctalTranslator {}
585                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b00100u32)))
586                .0,
587            "04"
588        );
589    }
590
591    #[test]
592    fn grouping_binary_translation_groups_digits_correctly_string() {
593        assert_eq!(
594            GroupingBinaryTranslator {}
595                .basic_translate(5, &VariableValue::String("1000w".to_string()))
596                .0,
597            "1 000w"
598        );
599        assert_eq!(
600            GroupingBinaryTranslator {}
601                .basic_translate(8, &VariableValue::String("100l00".to_string()))
602                .0,
603            "0010 0l00"
604        );
605        assert_eq!(
606            GroupingBinaryTranslator {}
607                .basic_translate(7, &VariableValue::String("10x00".to_string()))
608                .0,
609            "001 0x00"
610        );
611        assert_eq!(
612            GroupingBinaryTranslator {}
613                .basic_translate(7, &VariableValue::String("z10x00".to_string()))
614                .0,
615            "zz1 0x00"
616        );
617    }
618
619    #[test]
620    fn grouping_binary_translation_groups_digits_correctly_bigint() {
621        assert_eq!(
622            GroupingBinaryTranslator {}
623                .basic_translate(7, &VariableValue::BigUint(BigUint::from(0b100000u32)))
624                .0,
625            "010 0000"
626        );
627    }
628
629    #[test]
630    fn binary_translation_groups_digits_correctly_string() {
631        assert_eq!(
632            BinaryTranslator {}
633                .basic_translate(5, &VariableValue::String("10000".to_string()))
634                .0,
635            "10000"
636        );
637        assert_eq!(
638            BinaryTranslator {}
639                .basic_translate(8, &VariableValue::String("100h00".to_string()))
640                .0,
641            "00100h00"
642        );
643        assert_eq!(
644            BinaryTranslator {}
645                .basic_translate(7, &VariableValue::String("10x0-".to_string()))
646                .0,
647            "0010x0-"
648        );
649        assert_eq!(
650            BinaryTranslator {}
651                .basic_translate(7, &VariableValue::String("z10x00".to_string()))
652                .0,
653            "zz10x00"
654        );
655    }
656
657    #[test]
658    fn binary_translation_groups_digits_correctly_bigint() {
659        assert_eq!(
660            BinaryTranslator {}
661                .basic_translate(7, &VariableValue::BigUint(BigUint::from(0b100000u32)))
662                .0,
663            "0100000"
664        );
665    }
666
667    #[test]
668    fn ascii_translation_from_biguint() {
669        assert_eq!(
670            ASCIITranslator {}
671                .basic_translate(
672                    15,
673                    &VariableValue::BigUint(BigUint::from(0b100111101001011u32))
674                )
675                .0,
676            "OK"
677        );
678        assert_eq!(
679            ASCIITranslator {}
680                .basic_translate(72, &VariableValue::BigUint(BigUint::from(0b010011000110111101101110011001110010000001110100011001010111001101110100u128)))
681                .0,
682            "Long test"
683        );
684    }
685
686    #[test]
687    fn ascii_translation_from_string() {
688        assert_eq!(
689            ASCIITranslator {}
690                .basic_translate(15, &VariableValue::String("100111101001011".to_string()))
691                .0,
692            "OK"
693        );
694        assert_eq!(
695            ASCIITranslator {}
696                .basic_translate(
697                    72,
698                    &VariableValue::String(
699                        "010011000110111101101110011001110010000001110100011001010111001101110100"
700                            .to_string()
701                    )
702                )
703                .0,
704            "Long test"
705        );
706        assert_eq!(
707            ASCIITranslator {}
708                .basic_translate(16, &VariableValue::String("010x111101001011".to_string()))
709                .0,
710            "UNDEF"
711        );
712        // string too short for 2 characters, pads with 0
713        assert_eq!(
714            ASCIITranslator {}
715                .basic_translate(15, &VariableValue::String("11000001001011".to_string()))
716                .0,
717            "0K"
718        );
719    }
720
721    #[test]
722    fn bit_translation_from_biguint() {
723        assert_eq!(
724            BitTranslator {}
725                .basic_translate(1, &VariableValue::BigUint(BigUint::from(0b1u8)))
726                .0,
727            "1"
728        );
729        assert_eq!(
730            BitTranslator {}
731                .basic_translate(1, &VariableValue::BigUint(BigUint::from(0b0u8)))
732                .0,
733            "0"
734        );
735    }
736
737    #[test]
738    fn bit_translation_from_string() {
739        assert_eq!(
740            BitTranslator {}
741                .basic_translate(1, &VariableValue::String("1".to_string()))
742                .0,
743            "1"
744        );
745        assert_eq!(
746            BitTranslator {}
747                .basic_translate(1, &VariableValue::String("0".to_string()))
748                .0,
749            "0"
750        );
751        assert_eq!(
752            BitTranslator {}
753                .basic_translate(1, &VariableValue::String("x".to_string()))
754                .0,
755            "x"
756        );
757    }
758
759    #[test]
760    fn bit_translator_with_invalid_data() {
761        assert_eq!(
762            BitTranslator {}
763                .basic_translate(2, &VariableValue::BigUint(BigUint::from(3u8)))
764                .0,
765            "-"
766        );
767    }
768
769    #[test]
770    fn leb_translation_from_biguint() {
771        assert_eq!(
772            LebTranslator {}
773                .basic_translate(16, &VariableValue::BigUint(0b01011010_11101111u16.into()))
774                .0,
775            "11631"
776        );
777        assert_eq!(
778            LebTranslator {}
779                .basic_translate(16, &VariableValue::BigUint(0b00000000_00000001u16.into()))
780                .0,
781            "1"
782        );
783        assert_eq!(
784            LebTranslator{}.basic_translate(64, &VariableValue::BigUint(0b01001010_11110111_11101000_10100000_10111010_11110110_11100001_10011001u64.into())).0, "42185246214303897"
785        );
786    }
787    #[test]
788    fn leb_translation_from_string() {
789        assert_eq!(
790            LebTranslator {}
791                .basic_translate(16, &VariableValue::String("0111110011100010".to_owned()))
792                .0,
793            "15970"
794        );
795    }
796    #[test]
797    fn leb_translation_invalid_msb() {
798        assert_eq!(
799            LebTranslator {}
800                .basic_translate(16, &VariableValue::BigUint(0b1000000010000000u16.into()))
801                .0,
802            "invalid MSB: 1000 0000 1000 0000"
803        );
804    }
805    #[test]
806    fn leb_translation_invalid_continuation() {
807        assert_eq!(
808            LebTranslator {}
809                .basic_translate(16, &VariableValue::BigUint(0b0111111101111111u16.into()))
810                .0,
811            "invalid flag: 0111 1111 0111 1111"
812        );
813    }
814
815    #[test]
816    fn leb_tranlator_input_not_multiple_of_8() {
817        // act as if padded with 0s
818        assert_eq!(
819            LebTranslator {}
820                .basic_translate(16, &VariableValue::BigUint(0b00001111111u16.into()))
821                .0,
822            "127"
823        );
824    }
825
826    #[test]
827    fn number_of_ones_translation_string() {
828        assert_eq!(
829            NumberOfOnesTranslator {}
830                .basic_translate(5, &VariableValue::String("10000".to_string()))
831                .0,
832            "1"
833        );
834        assert_eq!(
835            NumberOfOnesTranslator {}
836                .basic_translate(5, &VariableValue::String("101".to_string()))
837                .0,
838            "2"
839        );
840        assert_eq!(
841            NumberOfOnesTranslator {}
842                .basic_translate(9, &VariableValue::String("1x100".to_string()))
843                .0,
844            "2"
845        );
846    }
847
848    #[test]
849    fn number_of_ones_translation_bigint() {
850        assert_eq!(
851            NumberOfOnesTranslator {}
852                .basic_translate(17, &VariableValue::BigUint(BigUint::from(0b101110000u32)))
853                .0,
854            "4"
855        );
856        assert_eq!(
857            NumberOfOnesTranslator {}
858                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
859                .0,
860            "1"
861        );
862    }
863
864    #[test]
865    fn trailing_ones_translation_string() {
866        assert_eq!(
867            TrailingOnesTranslator {}
868                .basic_translate(5, &VariableValue::String("10111".to_string()))
869                .0,
870            "3"
871        );
872        assert_eq!(
873            TrailingOnesTranslator {}
874                .basic_translate(5, &VariableValue::String("101".to_string()))
875                .0,
876            "1"
877        );
878        assert_eq!(
879            TrailingOnesTranslator {}
880                .basic_translate(9, &VariableValue::String("x100".to_string()))
881                .0,
882            "0"
883        );
884    }
885
886    #[test]
887    fn trailing_ones_translation_bigint() {
888        assert_eq!(
889            TrailingOnesTranslator {}
890                .basic_translate(17, &VariableValue::BigUint(BigUint::from(0b101111111u32)))
891                .0,
892            "7"
893        );
894        assert_eq!(
895            TrailingOnesTranslator {}
896                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
897                .0,
898            "0"
899        );
900        assert_eq!(
901            TrailingOnesTranslator {}
902                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b11111u32)))
903                .0,
904            "5"
905        );
906    }
907
908    #[test]
909    fn trailing_zeros_translation_string() {
910        assert_eq!(
911            TrailingZerosTranslator {}
912                .basic_translate(5, &VariableValue::String("10000".to_string()))
913                .0,
914            "4"
915        );
916        assert_eq!(
917            TrailingZerosTranslator {}
918                .basic_translate(5, &VariableValue::String("101".to_string()))
919                .0,
920            "0"
921        );
922        assert_eq!(
923            TrailingZerosTranslator {}
924                .basic_translate(9, &VariableValue::String("x100".to_string()))
925                .0,
926            "2"
927        );
928    }
929
930    #[test]
931    fn trailing_zeros_translation_bigint() {
932        assert_eq!(
933            TrailingZerosTranslator {}
934                .basic_translate(17, &VariableValue::BigUint(BigUint::from(0b101111111u32)))
935                .0,
936            "0"
937        );
938        assert_eq!(
939            TrailingZerosTranslator {}
940                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
941                .0,
942            "2"
943        );
944        assert_eq!(
945            TrailingZerosTranslator {}
946                .basic_translate(16, &VariableValue::BigUint(BigUint::from(0b0u32)))
947                .0,
948            "16"
949        );
950    }
951
952    #[test]
953    fn leading_ones_translation_string() {
954        assert_eq!(
955            LeadingOnesTranslator {}
956                .basic_translate(5, &VariableValue::String("11101".to_string()))
957                .0,
958            "3"
959        );
960        assert_eq!(
961            LeadingOnesTranslator {}
962                .basic_translate(5, &VariableValue::String("101".to_string()))
963                .0,
964            "0"
965        );
966        assert_eq!(
967            LeadingOnesTranslator {}
968                .basic_translate(9, &VariableValue::String("x100".to_string()))
969                .0,
970            "0"
971        );
972    }
973
974    #[test]
975    fn leading_ones_translation_bigint() {
976        assert_eq!(
977            LeadingOnesTranslator {}
978                .basic_translate(11, &VariableValue::BigUint(BigUint::from(0b11111111100u32)))
979                .0,
980            "9"
981        );
982        assert_eq!(
983            LeadingOnesTranslator {}
984                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
985                .0,
986            "0"
987        );
988        assert_eq!(
989            LeadingOnesTranslator {}
990                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b11111u32)))
991                .0,
992            "5"
993        );
994    }
995
996    #[test]
997    fn leading_zeros_translation_string() {
998        assert_eq!(
999            LeadingZerosTranslator {}
1000                .basic_translate(5, &VariableValue::String("10000".to_string()))
1001                .0,
1002            "0"
1003        );
1004        assert_eq!(
1005            LeadingZerosTranslator {}
1006                .basic_translate(5, &VariableValue::String("101".to_string()))
1007                .0,
1008            "2"
1009        );
1010        assert_eq!(
1011            LeadingZerosTranslator {}
1012                .basic_translate(9, &VariableValue::String("x100".to_string()))
1013                .0,
1014            "0"
1015        );
1016    }
1017
1018    #[test]
1019    fn leading_zeros_translation_bigint() {
1020        assert_eq!(
1021            LeadingZerosTranslator {}
1022                .basic_translate(17, &VariableValue::BigUint(BigUint::from(0b101111111u32)))
1023                .0,
1024            "8"
1025        );
1026        assert_eq!(
1027            LeadingZerosTranslator {}
1028                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
1029                .0,
1030            "37"
1031        );
1032        assert_eq!(
1033            LeadingZerosTranslator {}
1034                .basic_translate(16, &VariableValue::BigUint(BigUint::from(0b0u32)))
1035                .0,
1036            "16"
1037        );
1038    }
1039
1040    #[test]
1041    fn signbits_translation_string() {
1042        assert_eq!(
1043            IdenticalMSBsTranslator {}
1044                .basic_translate(5, &VariableValue::String("10000".to_string()))
1045                .0,
1046            "1"
1047        );
1048        assert_eq!(
1049            IdenticalMSBsTranslator {}
1050                .basic_translate(7, &VariableValue::String("0".to_string()))
1051                .0,
1052            "7"
1053        );
1054        assert_eq!(
1055            IdenticalMSBsTranslator {}
1056                .basic_translate(5, &VariableValue::String("101".to_string()))
1057                .0,
1058            "2"
1059        );
1060        assert_eq!(
1061            IdenticalMSBsTranslator {}
1062                .basic_translate(9, &VariableValue::String("x100".to_string()))
1063                .0,
1064            "0"
1065        );
1066        assert_eq!(
1067            IdenticalMSBsTranslator {}
1068                .basic_translate(5, &VariableValue::String("11101".to_string()))
1069                .0,
1070            "3"
1071        );
1072    }
1073
1074    #[test]
1075    fn signbits_translation_bigint() {
1076        assert_eq!(
1077            IdenticalMSBsTranslator {}
1078                .basic_translate(17, &VariableValue::BigUint(BigUint::from(0b101111111u32)))
1079                .0,
1080            "8"
1081        );
1082        assert_eq!(
1083            IdenticalMSBsTranslator {}
1084                .basic_translate(40, &VariableValue::BigUint(BigUint::from(0b00100u32)))
1085                .0,
1086            "37"
1087        );
1088        assert_eq!(
1089            IdenticalMSBsTranslator {}
1090                .basic_translate(16, &VariableValue::BigUint(BigUint::from(0b0u32)))
1091                .0,
1092            "16"
1093        );
1094        assert_eq!(
1095            IdenticalMSBsTranslator {}
1096                .basic_translate(11, &VariableValue::BigUint(BigUint::from(0b11111111100u32)))
1097                .0,
1098            "9"
1099        );
1100        assert_eq!(
1101            IdenticalMSBsTranslator {}
1102                .basic_translate(5, &VariableValue::BigUint(BigUint::from(0b11111u32)))
1103                .0,
1104            "5"
1105        );
1106    }
1107}