Skip to main content

rxing/aztec/encoder/
state.rs

1/*
2 * Copyright 2013 ZXing authors
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17use std::fmt;
18
19use crate::{
20    common::{BitArray, CharacterSet, Eci, Result},
21    exceptions::Exceptions,
22};
23
24use super::{HighLevelEncoder, Token};
25
26/**
27 * State represents all information about a sequence necessary to generate the current output.
28 * Note that a state is immutable.
29 */
30#[derive(Debug, Clone, PartialEq, Eq)]
31pub struct State {
32    // static final State INITIAL_STATE = new State(Token.EMPTY, HighLevelEncoder.MODE_UPPER, 0, 0);
33
34    // The current mode of the encoding (or the mode to which we'll return if
35    // we're in Binary Shift mode.
36    mode: u32,
37    // The list of tokens that we output.  If we are in Binary Shift mode, this
38    // token list does *not* yet included the token for those bytes
39    token: Token,
40    // If non-zero, the number of most recent bytes that should be output
41    // in Binary Shift mode.
42    binary_shift_byte_count: u32,
43    // The total number of bits generated (including Binary Shift).
44    bit_count: u32,
45    binary_shift_cost: u32,
46}
47impl State {
48    pub fn new(token: Token, mode: u32, binary_bytes: u32, bit_count: u32) -> Self {
49        Self {
50            mode,
51            token,
52            binary_shift_byte_count: binary_bytes,
53            bit_count,
54            binary_shift_cost: Self::calculate_binary_shift_cost(binary_bytes),
55        }
56    }
57
58    pub fn getMode(&self) -> u32 {
59        self.mode
60    }
61
62    pub fn getToken(&self) -> &Token {
63        &self.token
64    }
65
66    pub fn getBinaryShiftByteCount(&self) -> u32 {
67        self.binary_shift_byte_count
68    }
69
70    pub fn getBitCount(&self) -> u32 {
71        self.bit_count
72    }
73
74    pub fn appendFLGn(self, eci: Eci) -> Result<Self> {
75        let bit_count = self.bit_count;
76        let mode = self.mode;
77        let result = self.shiftAndAppend(HighLevelEncoder::MODE_PUNCT as u32, 0); // 0: FLG(n)
78        let mut token = result.token;
79        let mut bits_added = 3;
80        /*if eci < 0 {
81            token.add(0, 3); // 0: FNC1
82        } else */
83        if eci as u32 > 999999 {
84            return Err(Exceptions::illegal_argument_with(
85                "ECI code must be between 0 and 999999",
86            ));
87            // throw new IllegalArgumentException("ECI code must be between 0 and 999999");
88        } else {
89            let Ok(eci_digits) = CharacterSet::ISO8859_1.encode(&format!("{eci}")) else {
90                return Err(Exceptions::ILLEGAL_ARGUMENT);
91            };
92            // let eciDigits = Integer.toString(eci).getBytes(StandardCharsets.ISO_8859_1);
93            token.add(eci_digits.len() as i32, 3); // 1-6: number of ECI digits
94            for eci_digit in &eci_digits {
95                // for (byte eciDigit : eciDigits) {
96                token.add((eci_digit - b'0' + 2) as i32, 4);
97            }
98            bits_added += eci_digits.len() * 4;
99        }
100        Ok(State::new(token, mode, 0, bit_count + bits_added as u32))
101        // return new State(token, mode, 0, bitCount + bitsAdded);
102    }
103
104    // Create a new state representing this state with a latch to a (not
105    // necessary different) mode, and then a code.
106    pub fn latchAndAppend(self, mode: u32, value: u32) -> State {
107        let mut bitCount = self.bit_count;
108        let mut token = self.token;
109        if mode != self.mode {
110            let latch = HighLevelEncoder::LATCH_TABLE[self.mode as usize][mode as usize];
111            token.add(latch as i32 & 0xFFFF, latch >> 16);
112            bitCount += latch >> 16;
113        }
114        let latchModeBitCount = if mode == HighLevelEncoder::MODE_DIGIT as u32 {
115            4
116        } else {
117            5
118        };
119        token.add(value as i32, latchModeBitCount);
120
121        State::new(token, mode, 0, bitCount + latchModeBitCount)
122    }
123
124    // Create a new state representing this state, with a temporary shift
125    // to a different mode to output a single value.
126    pub fn shiftAndAppend(self, mode: u32, value: u32) -> State {
127        let mut token = self.token;
128        let thisModeBitCount = if self.mode == HighLevelEncoder::MODE_DIGIT as u32 {
129            4
130        } else {
131            5
132        };
133        // Shifts exist only to UPPER and PUNCT, both with tokens size 5.
134        token.add(
135            HighLevelEncoder::SHIFT_TABLE[self.mode as usize][mode as usize],
136            thisModeBitCount,
137        );
138        token.add(value as i32, 5);
139        State::new(token, self.mode, 0, self.bit_count + thisModeBitCount + 5)
140    }
141
142    // Create a new state representing this state, but an additional character
143    // output in Binary Shift mode.
144    pub fn addBinaryShiftChar(self, index: u32) -> State {
145        let mut token = self.token;
146        let mut mode = self.mode;
147        let mut bitCount = self.bit_count;
148        if self.mode == HighLevelEncoder::MODE_PUNCT as u32
149            || self.mode == HighLevelEncoder::MODE_DIGIT as u32
150        {
151            let latch = HighLevelEncoder::LATCH_TABLE[mode as usize][HighLevelEncoder::MODE_UPPER];
152            token.add(latch as i32 & 0xFFFF, latch >> 16);
153            bitCount += latch >> 16;
154            mode = HighLevelEncoder::MODE_UPPER as u32;
155        }
156        let deltaBitCount =
157            if self.binary_shift_byte_count == 0 || self.binary_shift_byte_count == 31 {
158                18
159            } else if self.binary_shift_byte_count == 62 {
160                9
161            } else {
162                8
163            };
164        let mut result = State::new(
165            token,
166            mode,
167            self.binary_shift_byte_count + 1,
168            bitCount + deltaBitCount,
169        );
170        if result.binary_shift_byte_count == 2047 + 31 {
171            // The string is as long as it's allowed to be.  We should end it.
172            result = result.endBinaryShift(index + 1);
173        }
174        result
175    }
176
177    // Create the state identical to this one, but we are no longer in
178    // Binary Shift mode.
179    pub fn endBinaryShift(self, index: u32) -> State {
180        if self.binary_shift_byte_count == 0 {
181            return self;
182        }
183        let mut token = self.token;
184        token.addBinaryShift(
185            index - self.binary_shift_byte_count,
186            self.binary_shift_byte_count,
187        );
188
189        State::new(token, self.mode, 0, self.bit_count)
190    }
191
192    // Returns true if "this" state is better (or equal) to be in than "that"
193    // state under all possible circumstances.
194    pub const fn isBetterThanOrEqualTo(&self, other: &State) -> bool {
195        let mut new_mode_bit_count = self.bit_count
196            + (HighLevelEncoder::LATCH_TABLE[self.mode as usize][other.mode as usize] >> 16);
197        if self.binary_shift_byte_count < other.binary_shift_byte_count {
198            // add additional B/S encoding cost of other, if any
199            new_mode_bit_count += other.binary_shift_cost - self.binary_shift_cost;
200        } else if self.binary_shift_byte_count > other.binary_shift_byte_count
201            && other.binary_shift_byte_count > 0
202        {
203            // maximum possible additional cost (we end up exceeding the 31 byte boundary and other state can stay beneath it)
204            new_mode_bit_count += 10;
205        }
206        new_mode_bit_count <= other.bit_count
207    }
208
209    pub fn toBitArray(self, text: &[u8]) -> Result<BitArray> {
210        let tok = self.endBinaryShift(text.len() as u32).token;
211
212        let symbols = tok.into_iter().collect::<Vec<_>>();
213
214        let mut bit_array = BitArray::new();
215        // Add each token to the result in forward order
216        for symbol in symbols.into_iter().rev() {
217            // for i in (0..symbols.len()).rev() {
218            // for (int i = symbols.size() - 1; i >= 0; i--) {
219            symbol.appendTo(&mut bit_array, text)?;
220        }
221        Ok(bit_array)
222    }
223
224    #[inline(always)]
225    const fn calculate_binary_shift_cost(binary_shift_byte_count: u32) -> u32 {
226        if binary_shift_byte_count > 62 {
227            21 // B/S with extended length
228        } else if binary_shift_byte_count > 31 {
229            20 // two B/S
230        } else if binary_shift_byte_count > 0 {
231            10 // one B/S
232        } else {
233            0
234        }
235    }
236}
237
238impl fmt::Display for State {
239    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240        write!(
241            f,
242            "{} bits={} bytes={}",
243            HighLevelEncoder::MODE_NAMES[self.mode as usize],
244            self.bit_count,
245            self.binary_shift_byte_count
246        )
247    }
248}