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