diff --git a/arithmetic-coding-core/src/model.rs b/arithmetic-coding-core/src/model.rs index eefa663..114de2a 100644 --- a/arithmetic-coding-core/src/model.rs +++ b/arithmetic-coding-core/src/model.rs @@ -67,6 +67,14 @@ pub trait Model { /// The internal representation to use for storing integers type B: BitStore = u32; + /// The maximum denominator used for probability ranges. See + /// [`Model::probability`]. + /// + /// This value is used to calculate an appropriate precision for the + /// encoding, therefore this value must not change, and + /// [`Model::denominator`] must never exceed it. + const MAX_DENOMINATOR: Self::B; + /// Given a symbol, return an interval representing the probability of that /// symbol occurring. /// @@ -98,17 +106,9 @@ pub trait Model { /// [`Encoder`](crate::Encoder) and [`Decoder`](crate::Decoder) to panic due /// to overflow or underflow. fn denominator(&self) -> Self::B { - self.max_denominator() + Self::MAX_DENOMINATOR } - /// The maximum denominator used for probability ranges. See - /// [`Model::probability`]. - /// - /// This value is used to calculate an appropriate precision for the - /// encoding, therefore this value must not change, and - /// [`Model::denominator`] must never exceed it. - fn max_denominator(&self) -> Self::B; - /// Given a value, return the symbol whose probability range it falls in. /// /// `None` indicates `EOF` diff --git a/arithmetic-coding-core/src/model/fixed_length.rs b/arithmetic-coding-core/src/model/fixed_length.rs index ba2a51a..e1541c4 100644 --- a/arithmetic-coding-core/src/model/fixed_length.rs +++ b/arithmetic-coding-core/src/model/fixed_length.rs @@ -72,6 +72,14 @@ pub trait Model { /// The internal representation to use for storing integers type B: BitStore = u32; + /// The maximum denominator used for probability ranges. See + /// [`Model::probability`]. + /// + /// This value is used to calculate an appropriate precision for the + /// encoding, therefore this value must not change, and + /// [`Model::denominator`] must never exceed it. + const MAX_DENOMINATOR: Self::B; + /// Given a symbol, return an interval representing the probability of that /// symbol occurring. /// @@ -100,17 +108,9 @@ pub trait Model { /// [`Encoder`](crate::Encoder) and [`Decoder`](crate::Decoder) to panic due /// to overflow or underflow. fn denominator(&self) -> Self::B { - self.max_denominator() + Self::MAX_DENOMINATOR } - /// The maximum denominator used for probability ranges. See - /// [`Model::probability`]. - /// - /// This value is used to calculate an appropriate precision for the - /// encoding, therefore this value must not change, and - /// [`Model::denominator`] must never exceed it. - fn max_denominator(&self) -> Self::B; - /// Given a value, return the symbol whose probability range it falls in. /// /// `None` indicates `EOF` @@ -154,9 +154,11 @@ impl crate::Model for Wrapper where M: Model, { - type B = M::B; type Symbol = M::Symbol; type ValueError = Error; + type B = M::B; + + const MAX_DENOMINATOR: Self::B = M::MAX_DENOMINATOR; fn probability( &self, @@ -179,8 +181,8 @@ where } } - fn max_denominator(&self) -> Self::B { - self.model.max_denominator() + fn denominator(&self) -> Self::B { + self.model.denominator() } fn symbol(&self, value: Self::B) -> Option { @@ -191,10 +193,6 @@ where } } - fn denominator(&self) -> Self::B { - self.model.denominator() - } - fn update(&mut self, symbol: Option<&Self::Symbol>) { if let Some(s) = symbol { self.model.update(s); diff --git a/arithmetic-coding-core/src/model/max_length.rs b/arithmetic-coding-core/src/model/max_length.rs index 9c45eea..92be93c 100644 --- a/arithmetic-coding-core/src/model/max_length.rs +++ b/arithmetic-coding-core/src/model/max_length.rs @@ -76,6 +76,14 @@ pub trait Model { /// The internal representation to use for storing integers type B: BitStore = u32; + /// The maximum denominator used for probability ranges. See + /// [`Model::probability`]. + /// + /// This value is used to calculate an appropriate precision for the + /// encoding, therefore this value must not change, and + /// [`Model::denominator`] must never exceed it. + const MAX_DENOMINATOR: Self::B; + /// Given a symbol, return an interval representing the probability of that /// symbol occurring. /// @@ -107,17 +115,9 @@ pub trait Model { /// [`Encoder`](crate::Encoder) and [`Decoder`](crate::Decoder) to panic due /// to overflow or underflow. fn denominator(&self) -> Self::B { - self.max_denominator() + Self::MAX_DENOMINATOR } - /// The maximum denominator used for probability ranges. See - /// [`Model::probability`]. - /// - /// This value is used to calculate an appropriate precision for the - /// encoding, therefore this value must not change, and - /// [`Model::denominator`] must never exceed it. - fn max_denominator(&self) -> Self::B; - /// Given a value, return the symbol whose probability range it falls in. /// /// `None` indicates `EOF` @@ -183,10 +183,6 @@ where } } - fn max_denominator(&self) -> Self::B { - self.model.max_denominator() - } - fn symbol(&self, value: Self::B) -> Option { if self.remaining > 0 { self.model.symbol(value) @@ -205,6 +201,8 @@ where self.remaining -= 1; } } + + const MAX_DENOMINATOR: Self::B = M::MAX_DENOMINATOR; } /// Fixed-length encoding/decoding errors diff --git a/arithmetic-coding-core/src/model/one_shot.rs b/arithmetic-coding-core/src/model/one_shot.rs index 13529f1..8aa7b9f 100644 --- a/arithmetic-coding-core/src/model/one_shot.rs +++ b/arithmetic-coding-core/src/model/one_shot.rs @@ -69,6 +69,14 @@ pub trait Model { /// The internal representation to use for storing integers type B: BitStore = u32; + /// The maximum denominator used for probability ranges. See + /// [`Model::probability`]. + /// + /// This value is used to calculate an appropriate precision for the + /// encoding, therefore this value must not change, and + /// [`Model::denominator`] must never exceed it. + const MAX_DENOMINATOR: Self::B; + /// Given a symbol, return an interval representing the probability of that /// symbol occurring. /// @@ -87,14 +95,6 @@ pub trait Model { /// This returns a custom error if the given symbol is not valid fn probability(&self, symbol: &Self::Symbol) -> Result, Self::ValueError>; - /// The maximum denominator used for probability ranges. See - /// [`Model::probability`]. - /// - /// This value is used to calculate an appropriate precision for the - /// encoding, therefore this value must not change, and - /// [`Model::denominator`] must never exceed it. - fn max_denominator(&self) -> Self::B; - /// Given a value, return the symbol whose probability range it falls in. /// /// `None` indicates `EOF` @@ -115,10 +115,6 @@ where Model::probability(self, symbol) } - fn max_denominator(&self) -> Self::B { - self.max_denominator() - } - fn symbol(&self, value: Self::B) -> Self::Symbol { Model::symbol(self, value) } @@ -128,6 +124,8 @@ where } fn denominator(&self) -> Self::B { - self.max_denominator() + Self::MAX_DENOMINATOR } + + const MAX_DENOMINATOR: Self::B = Self::MAX_DENOMINATOR; } diff --git a/benches/sherlock.rs b/benches/sherlock.rs index d967996..67b0aa8 100644 --- a/benches/sherlock.rs +++ b/benches/sherlock.rs @@ -5,15 +5,17 @@ use fenwick_model::{simple::FenwickModel, ValueError}; mod common; +const MAX_DENOMINATOR: u64 = 1 << 20; + #[derive(Debug, Clone)] pub struct StringModel { - fenwick_model: FenwickModel, + fenwick_model: FenwickModel, } impl StringModel { #[must_use] pub fn new(symbols: usize) -> Self { - let fenwick_model = FenwickModel::builder(symbols, 1 << 20) + let fenwick_model = FenwickModel::builder(symbols) .panic_on_saturation() .build(); Self { fenwick_model } @@ -41,13 +43,11 @@ impl Model for StringModel { self.fenwick_model.symbol(value).map(|x| x as u8) } - fn max_denominator(&self) -> Self::B { - self.fenwick_model.max_denominator() - } - fn denominator(&self) -> Self::B { self.fenwick_model.denominator() } + + const MAX_DENOMINATOR: Self::B = MAX_DENOMINATOR; } fn round_trip(input: &[u8]) { diff --git a/examples/concatenated.rs b/examples/concatenated.rs index abc41b8..509f233 100644 --- a/examples/concatenated.rs +++ b/examples/concatenated.rs @@ -40,9 +40,7 @@ mod integer { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } } @@ -81,9 +79,7 @@ mod symbolic { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } } diff --git a/examples/fenwick_adaptive.rs b/examples/fenwick_adaptive.rs index f7d33da..ee99736 100644 --- a/examples/fenwick_adaptive.rs +++ b/examples/fenwick_adaptive.rs @@ -9,16 +9,18 @@ use fenwick_model::{simple::FenwickModel, ValueError}; const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,\n-':()[]#*;\"!?*&é/àâè%@$"; +const MAX_DENOMINATOR: u64 = 1 << 20; + #[derive(Debug, Clone)] pub struct StringModel { alphabet: Vec, - fenwick_model: FenwickModel, + fenwick_model: FenwickModel, } impl StringModel { #[must_use] pub fn new(alphabet: Vec) -> Self { - let fenwick_model = FenwickModel::builder(alphabet.len(), 1 << 20) + let fenwick_model = FenwickModel::builder(alphabet.len()) .panic_on_saturation() .build(); Self { @@ -50,10 +52,6 @@ impl Model for StringModel { self.alphabet.get(index).copied() } - fn max_denominator(&self) -> Self::B { - self.fenwick_model.max_denominator() - } - fn denominator(&self) -> Self::B { self.fenwick_model.denominator() } @@ -62,6 +60,8 @@ impl Model for StringModel { let fenwick_symbol = symbol.map(|c| self.alphabet.iter().position(|x| x == c).unwrap()); self.fenwick_model.update(fenwick_symbol.as_ref()); } + + const MAX_DENOMINATOR: Self::B = MAX_DENOMINATOR; } fn main() { diff --git a/examples/fenwick_context_switching.rs b/examples/fenwick_context_switching.rs index 77a1ffc..54b4f4b 100644 --- a/examples/fenwick_context_switching.rs +++ b/examples/fenwick_context_switching.rs @@ -9,16 +9,18 @@ use fenwick_model::{context_switching::FenwickModel, ValueError}; const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,\n-':()[]#*;\"!?*&é/àâè%@$"; +const MAX_DENOMINATOR: u64 = 1 << 17; + #[derive(Debug, Clone)] pub struct StringModel { alphabet: Vec, - fenwick_model: FenwickModel, + fenwick_model: FenwickModel, } impl StringModel { #[must_use] pub fn new(alphabet: Vec) -> Self { - let fenwick_model = FenwickModel::with_symbols(alphabet.len(), 1 << 17); + let fenwick_model = FenwickModel::with_symbols(alphabet.len()); Self { alphabet, fenwick_model, @@ -48,10 +50,6 @@ impl Model for StringModel { self.alphabet.get(index).copied() } - fn max_denominator(&self) -> Self::B { - self.fenwick_model.max_denominator() - } - fn denominator(&self) -> Self::B { self.fenwick_model.denominator() } @@ -60,6 +58,8 @@ impl Model for StringModel { let fenwick_symbol = symbol.map(|c| self.alphabet.iter().position(|x| x == c).unwrap()); self.fenwick_model.update(fenwick_symbol.as_ref()); } + + const MAX_DENOMINATOR: Self::B = MAX_DENOMINATOR; } fn main() { diff --git a/examples/fixed_length.rs b/examples/fixed_length.rs index f0bfa5e..5482ec1 100644 --- a/examples/fixed_length.rs +++ b/examples/fixed_length.rs @@ -38,13 +38,11 @@ impl fixed_length::Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 3 - } - fn length(&self) -> usize { 3 } + + const MAX_DENOMINATOR: Self::B = 3; } fn main() { diff --git a/examples/integer.rs b/examples/integer.rs index 773b4e4..c59169b 100644 --- a/examples/integer.rs +++ b/examples/integer.rs @@ -37,9 +37,7 @@ impl Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } fn main() { diff --git a/examples/max_length.rs b/examples/max_length.rs index 7911632..f9fe852 100644 --- a/examples/max_length.rs +++ b/examples/max_length.rs @@ -40,13 +40,13 @@ impl max_length::Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 4 - } - fn max_length(&self) -> usize { 3 } + + type B = u32; + + const MAX_DENOMINATOR: Self::B = 4; } fn main() { diff --git a/examples/sherlock.rs b/examples/sherlock.rs index 41e84df..3c2d822 100644 --- a/examples/sherlock.rs +++ b/examples/sherlock.rs @@ -7,14 +7,16 @@ mod common; const ALPHABET: &str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 .,\n-':()[]#*;\"!?*&é/àâè%@$"; +const ALPHABET_LEN: usize = ALPHABET.len(); + #[derive(Debug, Clone)] -pub struct StringModel { - alphabet: Vec, +pub struct StringModel<'a, const ALPHABET_LEN: usize> { + alphabet: &'a str, } -impl StringModel { +impl<'a, const ALPHABET_LEN: usize> StringModel<'a, ALPHABET_LEN> { #[must_use] - pub fn new(alphabet: Vec) -> Self { + pub fn new(alphabet: &'a str) -> Self { Self { alphabet } } } @@ -23,14 +25,14 @@ impl StringModel { #[error("invalid character: {0}")] pub struct Error(char); -impl Model for StringModel { +impl<'a, const ALPHABET_LEN: usize> Model for StringModel<'a, ALPHABET_LEN> { type B = usize; type Symbol = char; type ValueError = Error; fn probability(&self, symbol: Option<&Self::Symbol>) -> Result, Error> { if let Some(char) = symbol { - match self.alphabet.iter().position(|x| x == char) { + match self.alphabet.chars().position(|x| x == *char) { Some(index) => Ok(index..(index + 1)), None => Err(Error(*char)), } @@ -41,12 +43,10 @@ impl Model for StringModel { } fn symbol(&self, value: usize) -> Option { - self.alphabet.get(value).copied() + self.alphabet.chars().nth(value) } - fn max_denominator(&self) -> usize { - self.alphabet.len() + 1 - } + const MAX_DENOMINATOR: Self::B = ALPHABET_LEN + 1; } fn main() { @@ -55,7 +55,7 @@ fn main() { file.read_to_string(&mut input).unwrap(); let input_bytes = input.bytes().len(); - let model = StringModel::new(ALPHABET.chars().collect()); + let model = StringModel::::new(ALPHABET); let buffer = common::encode(model.clone(), input.chars()); diff --git a/examples/symbolic.rs b/examples/symbolic.rs index e16c8c2..e1c9bda 100644 --- a/examples/symbolic.rs +++ b/examples/symbolic.rs @@ -40,9 +40,7 @@ impl Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } fn main() { diff --git a/fenwick-model/src/context_switching.rs b/fenwick-model/src/context_switching.rs index 9938118..66e981c 100644 --- a/fenwick-model/src/context_switching.rs +++ b/fenwick-model/src/context_switching.rs @@ -6,15 +6,14 @@ use super::Weights; use crate::ValueError; #[derive(Debug, Clone)] -pub struct FenwickModel { +pub struct FenwickModel { contexts: Vec, current_context: usize, - max_denominator: u64, } -impl FenwickModel { +impl FenwickModel { #[must_use] - pub fn with_symbols(symbols: usize, max_denominator: u64) -> Self { + pub fn with_symbols(symbols: usize) -> Self { let mut contexts = Vec::with_capacity(symbols + 1); for _ in 0..=symbols { @@ -24,7 +23,6 @@ impl FenwickModel { Self { contexts, current_context: 1, - max_denominator, } } @@ -37,7 +35,7 @@ impl FenwickModel { } } -impl Model for FenwickModel { +impl Model for FenwickModel { type B = u64; type Symbol = usize; type ValueError = ValueError; @@ -50,22 +48,20 @@ impl Model for FenwickModel { self.context().total } - fn max_denominator(&self) -> u64 { - self.max_denominator - } - fn symbol(&self, value: u64) -> Option { self.context().symbol(value) } fn update(&mut self, symbol: Option<&usize>) { debug_assert!( - self.denominator() < self.max_denominator, + self.denominator() < MAX_DENOMINATOR, "hit max denominator!" ); - if self.denominator() < self.max_denominator { + if self.denominator() < MAX_DENOMINATOR { self.context_mut().update(symbol.copied(), 1); } self.current_context = symbol.map(|x| x + 1).unwrap_or_default(); } + + const MAX_DENOMINATOR: Self::B = MAX_DENOMINATOR; } diff --git a/fenwick-model/src/simple.rs b/fenwick-model/src/simple.rs index 1d0c1f8..1a7650e 100644 --- a/fenwick-model/src/simple.rs +++ b/fenwick-model/src/simple.rs @@ -7,23 +7,21 @@ use super::Weights; use crate::ValueError; #[derive(Debug, Clone)] -pub struct FenwickModel { +pub struct FenwickModel { weights: Weights, - max_denominator: u64, panic_on_saturation: bool, } #[must_use] -pub struct Builder { - model: FenwickModel, +pub struct Builder { + model: FenwickModel, } -impl Builder { - fn new(n_symbols: usize, max_denominator: u64) -> Self { +impl Builder { + fn new(n_symbols: usize) -> Self { let weights = Weights::new(n_symbols); let model = FenwickModel { weights, - max_denominator, panic_on_saturation: false, }; Self { model } @@ -35,18 +33,18 @@ impl Builder { } #[must_use] - pub fn build(self) -> FenwickModel { + pub fn build(self) -> FenwickModel { self.model } } -impl FenwickModel { - pub fn builder(n_symbols: usize, max_denominator: u64) -> Builder { - Builder::new(n_symbols, max_denominator) +impl FenwickModel { + pub fn builder(n_symbols: usize) -> Builder { + Builder::new(n_symbols) } } -impl Model for FenwickModel { +impl Model for FenwickModel { type B = u64; type Symbol = usize; type ValueError = ValueError; @@ -66,10 +64,6 @@ impl Model for FenwickModel { } } - fn max_denominator(&self) -> Self::B { - self.max_denominator - } - fn symbol(&self, value: Self::B) -> Option { self.weights.symbol(value) } @@ -81,12 +75,14 @@ impl Model for FenwickModel { fn update(&mut self, symbol: Option<&Self::Symbol>) { if self.panic_on_saturation { debug_assert!( - self.denominator() < self.max_denominator, + self.denominator() < MAX_DENOMINATOR, "hit max denominator!" ); } - if self.denominator() < self.max_denominator { + if self.denominator() < MAX_DENOMINATOR { self.weights.update(symbol.copied(), 1); } } + + const MAX_DENOMINATOR: Self::B = MAX_DENOMINATOR; } diff --git a/src/decoder.rs b/src/decoder.rs index 35d5a40..d5c9e97 100644 --- a/src/decoder.rs +++ b/src/decoder.rs @@ -59,7 +59,7 @@ where /// If these constraints cannot be satisfied this method will panic in debug /// builds pub fn new(model: M, input: R) -> Self { - let frequency_bits = model.max_denominator().log2() + 1; + let frequency_bits = M::MAX_DENOMINATOR.log2() + 1; let precision = M::B::BITS - frequency_bits; Self::with_precision(model, input, precision) @@ -79,7 +79,7 @@ where /// If these constraints cannot be satisfied this method will panic in debug /// builds pub fn with_precision(model: M, input: R, precision: u32) -> Self { - let frequency_bits = model.max_denominator().log2() + 1; + let frequency_bits = M::MAX_DENOMINATOR.log2() + 1; debug_assert!( (precision >= (frequency_bits + 2)), "not enough bits of precision to prevent overflow/underflow", @@ -118,7 +118,7 @@ where let denominator = self.model.denominator(); debug_assert!( - denominator <= self.model.max_denominator(), + denominator <= M::MAX_DENOMINATOR, "denominator is greater than maximum!" ); let value = self.state.value(denominator); diff --git a/src/encoder.rs b/src/encoder.rs index 226b5a8..7a34763 100644 --- a/src/encoder.rs +++ b/src/encoder.rs @@ -46,7 +46,7 @@ where /// If these constraints cannot be satisfied this method will panic in debug /// builds pub fn new(model: M, bitwriter: &'a mut W) -> Self { - let frequency_bits = model.max_denominator().log2() + 1; + let frequency_bits = M::MAX_DENOMINATOR.log2() + 1; let precision = M::B::BITS - frequency_bits; Self::with_precision(model, bitwriter, precision) } @@ -65,7 +65,7 @@ where /// If these constraints cannot be satisfied this method will panic in debug /// builds pub fn with_precision(model: M, bitwriter: &'a mut W, precision: u32) -> Self { - let frequency_bits = model.max_denominator().log2() + 1; + let frequency_bits = M::MAX_DENOMINATOR.log2() + 1; debug_assert!( (precision >= (frequency_bits + 2)), "not enough bits of precision to prevent overflow/underflow", @@ -125,7 +125,7 @@ where let p = self.model.probability(symbol).map_err(Error::ValueError)?; let denominator = self.model.denominator(); debug_assert!( - denominator <= self.model.max_denominator(), + denominator <= M::MAX_DENOMINATOR, "denominator is greater than maximum!" ); diff --git a/tests/concatenated.rs b/tests/concatenated.rs index eb73c94..5bc25c3 100644 --- a/tests/concatenated.rs +++ b/tests/concatenated.rs @@ -41,9 +41,7 @@ mod integer { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } } @@ -82,9 +80,7 @@ mod symbolic { } } - fn max_denominator(&self) -> u32 { - 4 - } + const MAX_DENOMINATOR: Self::B = 4; } } diff --git a/tests/fixed_length.rs b/tests/fixed_length.rs index b0e99a3..531ed92 100644 --- a/tests/fixed_length.rs +++ b/tests/fixed_length.rs @@ -38,13 +38,13 @@ impl fixed_length::Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 3 - } - fn length(&self) -> usize { 3 } + + type B = u32; + + const MAX_DENOMINATOR: Self::B = 3; } #[test] diff --git a/tests/fuzz.rs b/tests/fuzz.rs index ba58d67..9e95c5a 100644 --- a/tests/fuzz.rs +++ b/tests/fuzz.rs @@ -2,9 +2,11 @@ use fenwick_model::simple::FenwickModel; mod common; +const MAX_DENOMINATOR: u64 = 1 << 20; + #[test] fn round_trip() { - let model = FenwickModel::builder(256, 1 << 20).build(); + let model = FenwickModel::::builder(256).build(); let bytes: &[u8] = &[220, 255, 255]; let input: Vec = bytes.iter().copied().map(usize::from).collect(); diff --git a/tests/max_length.rs b/tests/max_length.rs index 79ec3c6..f0e5fb7 100644 --- a/tests/max_length.rs +++ b/tests/max_length.rs @@ -41,13 +41,11 @@ impl max_length::Model for MyModel { } } - fn max_denominator(&self) -> u32 { - 4 - } - fn max_length(&self) -> usize { 3 } + + const MAX_DENOMINATOR: Self::B = 4; } #[test_case(&[Symbol::A, Symbol::B] ; "shorter")] diff --git a/tests/sherlock.rs b/tests/sherlock.rs index 0a3c570..188fdf4 100644 --- a/tests/sherlock.rs +++ b/tests/sherlock.rs @@ -34,9 +34,7 @@ impl Model for StringModel { ALPHABET.chars().nth(value) } - fn max_denominator(&self) -> Self::B { - ALPHABET.len() + 1 - } + const MAX_DENOMINATOR: Self::B = ALPHABET.len() + 1; } #[test]