Struct tfm::NextLargerProgram
source · pub struct NextLargerProgram { /* private fields */ }
Expand description
Compiled program of “next larger character” instructions
The .tfm file format can associate a “next larger” character to any character in a font. Next larger characters form sequences: i.e. B can be the next larger character for A, and C can be the next larger character for B, leading to the sequences A-B-C. These next larger characters are used at certain points in TeX. TeX occasionally traverses the entire sequence for a given starting character (e.g. A).
As with ligatures, next larger specifications can contain infinite loops - e.g, if X is the next larger character for Y and Y is the next larger character for X. These loops are invalid and removed by TFtoPL and PLtoTF.
Motivated by the idea of “parse don’t validate”, this type represents a compiled version of the next larger specifications in which infinite loops are statically guaranteed not to exist.
The basic use of a valid program looks like this:
let edges = vec![
(Char::A, Char::B),
(Char::B, Char::C),
];
let (next_larger_program, warnings) = NextLargerProgram::new(edges.into_iter(), |_| true, true);
assert_eq![warnings, vec![]];
let sequence_A: Vec<Char> = next_larger_program.get(Char::A).collect();
assert_eq!(sequence_A, vec![Char::B, Char::C]);
let sequence_B: Vec<Char> = next_larger_program.get(Char::B).collect();
assert_eq!(sequence_B, vec![Char::C]);
let sequence_C: Vec<Char> = next_larger_program.get(Char::C).collect();
assert_eq!(sequence_C, vec![]);
// Character that is not in the program.
let sequence_D: Vec<Char> = next_larger_program.get(Char::D).collect();
assert_eq!(sequence_D, vec![]);
Warnings
There are two types of error that can occur when constructing the next
larger program.
Both of these errors are handled gracefully, so we officially refer to them as warnings.
The constructor returns them as values of type NextLargerProgramWarning
.
Infinite loops
The first error is that next larger programs can contain infinite loops -
e.g, if X is the next larger character for Y
and Y is the next larger character for X.
In this case the loop is broken by removing the next larger program for the
character with the largest 8-bit code, in this case Y.
A NextLargerProgramWarning::InfiniteLoop
warning is returned
from the program constructor.
let edges = vec![
(Char::X, Char::Y),
(Char::Y, Char::X),
];
let (next_larger_program, warnings) = NextLargerProgram::new(edges.into_iter(), |_| true, true);
assert_eq!(warnings, vec![NextLargerProgramWarning::InfiniteLoop{
original: Char::Y,
next_larger: Char::X,
}]);
let sequence_X: Vec<Char> = next_larger_program.get(Char::X).collect();
assert_eq!(sequence_X, vec![Char::Y]);
let sequence_Y: Vec<Char> = next_larger_program.get(Char::Y).collect();
assert_eq!(sequence_Y, vec![]);
Non-existent characters
The second error is that characters referred to in the next larger program
may not be defined in the .tfm or .pl file.
For example, a .pl file may contain the snippet (CHARACTER C X (NEXTLARGER C Y))
without defining the character Y.
The constructor NextLargerProgram::new
accepts a function for checking if a
character exists.
In all cases a NextLargerProgramWarning::NonExistentCharacter
warning is returned
if a non-existent character is encountered.
The behavior of the resulting next larger program is configured using the
drop_non_existent_characters
argument.
If this is false, then the behavior is the same as PLtoTF and the program still
contains the character.
let edges = vec![
(Char::X, Char::Y),
];
let character_exists = |c| {
if c == Char::Y {
false
} else {
true
}
};
let (next_larger_program, warnings) = NextLargerProgram::new(edges.into_iter(), character_exists, false);
assert_eq!(warnings, vec![NextLargerProgramWarning::NonExistentCharacter{
original: Char::X,
next_larger: Char::Y,
}]);
let sequence_X: Vec<Char> = next_larger_program.get(Char::X).collect();
assert_eq!(sequence_X, vec![Char::Y]);
If drop_non_existent_characters
is true, next larger instructions pointing at non-existent
characters are dropped.
This is how TFtoPL behaves.
let edges = vec![
(Char::X, Char::Y),
];
let character_exists = |c| {
if c == Char::Y {
false
} else {
true
}
};
let (next_larger_program, warnings) = NextLargerProgram::new(edges.into_iter(), character_exists, true);
assert_eq!(warnings, vec![NextLargerProgramWarning::NonExistentCharacter{
original: Char::X,
next_larger: Char::Y,
}]);
let sequence_X: Vec<Char> = next_larger_program.get(Char::X).collect();
assert_eq!(sequence_X, vec![]);
Implementations§
source§impl NextLargerProgram
impl NextLargerProgram
sourcepub fn new<I: Iterator<Item = (Char, Char)>, F: Fn(Char) -> bool>(
edges: I,
character_exists: F,
drop_non_existent_characters: bool
) -> (Self, Vec<NextLargerProgramWarning>)
pub fn new<I: Iterator<Item = (Char, Char)>, F: Fn(Char) -> bool>( edges: I, character_exists: F, drop_non_existent_characters: bool ) -> (Self, Vec<NextLargerProgramWarning>)
Build a new next larger program from an iterator over edges.
sourcepub fn get(&self, c: Char) -> impl Iterator<Item = Char> + '_
pub fn get(&self, c: Char) -> impl Iterator<Item = Char> + '_
Get the next larger sequence for a character
sourcepub fn is_seven_bit_safe(&self) -> bool
pub fn is_seven_bit_safe(&self) -> bool
Returns whether this program is seven-bit safe.
A next larger program is seven-bit safe if the next larger sequences for seven-bit characters only contain seven-bit characters. Conversely a program is seven-bit unsafe if there is a seven-bit character whose next larger sequence contains a non-seven-bit character.
let edges = vec![
(Char(250), Char(125)),
(Char(125), Char(126)),
];
let (next_larger_program, _) = NextLargerProgram::new(edges.into_iter(), |_| true, true);
assert_eq!(true, next_larger_program.is_seven_bit_safe());
let edges = vec![
(Char(125), Char(250)),
];
let (next_larger_program, _) = NextLargerProgram::new(edges.into_iter(), |_| true, true);
assert_eq!(false, next_larger_program.is_seven_bit_safe());
Trait Implementations§
source§impl Clone for NextLargerProgram
impl Clone for NextLargerProgram
source§fn clone(&self) -> NextLargerProgram
fn clone(&self) -> NextLargerProgram
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read more