#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
pub enum TextDirection {
#[default]
LeftToRight,
RightToLeft,
}
impl TextDirection {
pub const fn is_right_to_left(self) -> bool {
matches!(self, Self::RightToLeft)
}
pub const fn begin_fraction_to_left_fraction(self, begin_fraction: f32) -> f32 {
match self {
Self::LeftToRight => begin_fraction,
Self::RightToLeft => 1.0 - begin_fraction,
}
}
pub const fn left_fraction_to_begin_fraction(self, left_fraction: f32) -> f32 {
self.begin_fraction_to_left_fraction(left_fraction)
}
pub const fn begin_step_to_left_step(self, begin_step: i32) -> i32 {
match self {
Self::LeftToRight => begin_step,
Self::RightToLeft => -begin_step,
}
}
}
#[cfg(test)]
mod tests {
use super::TextDirection;
#[test]
fn the_default_direction_is_left_to_right() {
assert_eq!(TextDirection::default(), TextDirection::LeftToRight);
assert!(!TextDirection::default().is_right_to_left());
}
#[test]
fn the_beginning_of_the_line_is_at_opposite_ends() {
let ltr = TextDirection::LeftToRight;
let rtl = TextDirection::RightToLeft;
assert_eq!(ltr.begin_fraction_to_left_fraction(0.0), 0.0);
assert_eq!(rtl.begin_fraction_to_left_fraction(0.0), 1.0);
assert_eq!(ltr.begin_fraction_to_left_fraction(1.0), 1.0);
assert_eq!(rtl.begin_fraction_to_left_fraction(1.0), 0.0);
assert_eq!(ltr.begin_fraction_to_left_fraction(0.5), 0.5);
assert_eq!(rtl.begin_fraction_to_left_fraction(0.5), 0.5);
}
#[test]
fn the_two_conversions_are_inverses() {
for direction in [TextDirection::LeftToRight, TextDirection::RightToLeft] {
for step in 0..=10 {
let begin_fraction = step as f32 / 10.0;
let left = direction.begin_fraction_to_left_fraction(begin_fraction);
let back = direction.left_fraction_to_begin_fraction(left);
assert!(
(back - begin_fraction).abs() < f32::EPSILON,
"{direction:?}: {begin_fraction} round-tripped to {back}"
);
}
}
}
#[test]
fn a_step_toward_the_maximum_follows_the_direction() {
assert_eq!(TextDirection::LeftToRight.begin_step_to_left_step(1), 1);
assert_eq!(TextDirection::RightToLeft.begin_step_to_left_step(1), -1);
assert_eq!(TextDirection::LeftToRight.begin_step_to_left_step(-1), -1);
assert_eq!(TextDirection::RightToLeft.begin_step_to_left_step(-1), 1);
}
#[test]
fn mirroring_the_line_and_the_step_agree() {
for direction in [TextDirection::LeftToRight, TextDirection::RightToLeft] {
let flipped = if direction.is_right_to_left() {
TextDirection::LeftToRight
} else {
TextDirection::RightToLeft
};
assert_eq!(
direction.begin_fraction_to_left_fraction(0.0),
flipped.begin_fraction_to_left_fraction(1.0)
);
assert_eq!(
direction.begin_fraction_to_left_fraction(1.0),
flipped.begin_fraction_to_left_fraction(0.0)
);
assert_eq!(
direction.begin_step_to_left_step(1),
-flipped.begin_step_to_left_step(1),
"{direction:?} and {flipped:?} must disagree about which way is forward"
);
}
}
}