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