1use crate::picture::Sym;
5
6pub fn numeric(syms: &[Sym], digits: u32, negative: bool, magnitude: u128, blank_when_zero: bool, point: char) -> String {
10 let size: usize = syms.iter().map(Sym::width).sum();
11 let digit_syms: Vec<&Sym> = syms.iter().filter(|s| s.is_digit()).collect();
12 if magnitude == 0 && (blank_when_zero || digit_syms.iter().all(|s| matches!(s, Sym::Z | Sym::Float(_)))) {
13 return " ".repeat(size);
14 }
15 if magnitude == 0 && digit_syms.iter().all(|s| matches!(s, Sym::Star)) {
16 return syms.iter().flat_map(|s| std::iter::repeat_n(if *s == Sym::Point { point } else { '*' }, s.width())).collect();
17 }
18 let text = format!("{magnitude:0width$}", width = digits as usize);
19 let mut digit_chars = text.chars().skip(text.len() - digits as usize);
20 let mut out: Vec<char> = Vec::with_capacity(size);
21 let (mut significant, mut fill) = (false, None);
22 let (mut float_char, mut float_slot) = (None, None);
23 for s in syms {
24 match *s {
25 Sym::Nine => {
26 significant = true;
27 out.push(digit_chars.next().unwrap_or('0'));
28 }
29 Sym::Z | Sym::Star => {
30 let blank = if *s == Sym::Star { '*' } else { ' ' };
31 fill = Some(blank);
32 let d = digit_chars.next().unwrap_or('0');
33 significant |= d != '0';
34 out.push(if significant { d } else { blank });
35 }
36 Sym::FloatLead(c) => {
37 float_char = Some(c);
38 float_slot = Some(out.len());
39 out.push(' ');
40 }
41 Sym::Float(_) => {
42 let d = digit_chars.next().unwrap_or('0');
43 significant |= d != '0';
44 if significant {
45 out.push(d);
46 } else {
47 float_slot = Some(out.len());
48 out.push(' ');
49 }
50 }
51 Sym::Point | Sym::Implied => {
52 significant = true;
53 if *s == Sym::Point {
54 out.push(point);
55 }
56 }
57 Sym::Insert(c) => {
58 if significant {
59 out.push(c);
60 } else if float_char.is_some() {
61 float_slot = Some(out.len());
62 out.push(' ');
63 } else {
64 out.push(fill.unwrap_or(c));
65 }
66 }
67 Sym::Sign(c) => out.push(match (c, negative) {
68 ('+', false) => '+',
69 (_, true) => '-',
70 _ => ' ',
71 }),
72 Sym::Currency => out.push('$'),
73 Sym::Cr => out.extend(if negative { ['C', 'R'] } else { [' ', ' '] }),
74 Sym::Db => out.extend(if negative { ['D', 'B'] } else { [' ', ' '] }),
75 Sym::Char => out.push(' '),
76 }
77 }
78 if let (Some(c), Some(slot)) = (float_char, float_slot) {
79 out[slot] = match (c, negative) {
80 ('$', _) => '$',
81 ('+', false) => '+',
82 (_, true) => '-',
83 _ => ' ',
84 };
85 }
86 out.into_iter().collect()
87}
88
89pub fn alphanumeric(syms: &[Sym], data: &[u8], space: u8, encode: impl Fn(char) -> u8) -> Vec<u8> {
92 let mut source = data.iter();
93 syms.iter()
94 .map(|s| match s {
95 Sym::Insert(c) => encode(*c),
96 _ => source.next().copied().unwrap_or(space),
97 })
98 .collect()
99}
100
101pub fn de_edit(syms: &[Sym], text: &str) -> (bool, u128) {
104 let chars: Vec<char> = text.chars().collect();
105 let (mut at, mut magnitude, mut negative) = (0usize, 0u128, false);
106 for s in syms {
107 let c = chars.get(at).copied().unwrap_or(' ');
108 match s {
109 Sym::Implied => continue,
110 Sym::Cr | Sym::Db => {
111 negative |= c != ' ';
112 at += 2;
113 continue;
114 }
115 _ if s.is_digit() => magnitude = magnitude * 10 + c.to_digit(10).unwrap_or(0) as u128,
116 Sym::Sign(_) | Sym::FloatLead(_) | Sym::Float(_) => negative |= c == '-',
117 _ => {}
118 }
119 if matches!(s, Sym::Float(_)) {
120 negative |= c == '-';
121 }
122 at += 1;
123 }
124 (negative, magnitude)
125}