libsurfer/translation/
basic_translators.rs

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