Skip to content

Commit

Permalink
Merge pull request #480 from mgeisler/options-non-exhaustive
Browse files Browse the repository at this point in the history
Mark `Options` as `non_exhaustive`
  • Loading branch information
mgeisler authored Oct 23, 2022
2 parents ff039c2 + 5fe6800 commit 0c9bbea
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 43 deletions.
76 changes: 34 additions & 42 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,7 @@ pub mod core;
pub mod fuzzing;

/// Holds configuration options for wrapping and filling text.
#[non_exhaustive]
#[derive(Debug, Clone)]
pub struct Options<'a> {
/// The width in columns at which the text will be wrapped.
Expand Down Expand Up @@ -280,36 +281,30 @@ impl<'a> From<usize> for Options<'a> {
}

impl<'a> Options<'a> {
/// Creates a new [`Options`] with the specified width. Equivalent to
/// Creates a new [`Options`] with the specified width.
///
/// The other fields are given default values as follows:
///
/// ```
/// # use textwrap::{LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm};
/// # let width = 80;
/// # let actual = Options::new(width);
/// # let expected =
/// Options {
/// width: width,
/// line_ending: LineEnding::LF,
/// initial_indent: "",
/// subsequent_indent: "",
/// break_words: true,
/// #[cfg(feature = "unicode-linebreak")]
/// word_separator: WordSeparator::UnicodeBreakProperties,
/// #[cfg(not(feature = "unicode-linebreak"))]
/// word_separator: WordSeparator::AsciiSpace,
/// #[cfg(feature = "smawk")]
/// wrap_algorithm: WrapAlgorithm::new_optimal_fit(),
/// #[cfg(not(feature = "smawk"))]
/// wrap_algorithm: WrapAlgorithm::FirstFit,
/// word_splitter: WordSplitter::HyphenSplitter,
/// }
/// # ;
/// # assert_eq!(actual.width, expected.width);
/// # assert_eq!(actual.line_ending, expected.line_ending);
/// # assert_eq!(actual.initial_indent, expected.initial_indent);
/// # assert_eq!(actual.subsequent_indent, expected.subsequent_indent);
/// # assert_eq!(actual.break_words, expected.break_words);
/// # assert_eq!(actual.word_splitter, expected.word_splitter);
/// let options = Options::new(width);
/// assert_eq!(options.line_ending, LineEnding::LF);
/// assert_eq!(options.initial_indent, "");
/// assert_eq!(options.subsequent_indent, "");
/// assert_eq!(options.break_words, true);
///
/// #[cfg(feature = "unicode-linebreak")]
/// assert_eq!(options.word_separator, WordSeparator::UnicodeBreakProperties);
/// #[cfg(not(feature = "unicode-linebreak"))]
/// assert_eq!(options.word_separator, WordSeparator::AsciiSpace);
///
/// #[cfg(feature = "smawk")]
/// assert_eq!(options.wrap_algorithm, WrapAlgorithm::new_optimal_fit());
/// #[cfg(not(feature = "smawk"))]
/// assert_eq!(options.wrap_algorithm, WrapAlgorithm::FirstFit);
///
/// assert_eq!(options.word_splitter, WordSplitter::HyphenSplitter);
/// ```
///
/// Note that the default word separator and wrap algorithms
Expand Down Expand Up @@ -1218,26 +1213,23 @@ where
/// text remains untouched.
///
/// Since we can only replace existing whitespace in the input with
/// `'\n'`, we cannot do hyphenation nor can we split words longer
/// than the line width. We also need to use `AsciiSpace` as the word
/// separator since we need `' '` characters between words in order to
/// replace some of them with a `'\n'`. Indentation is also ruled out.
/// In other words, `fill_inplace(width)` behaves as if you had called
/// [`fill`] with these options:
/// `'\n'` (there is no space for `"\r\n"`), we cannot do hyphenation
/// nor can we split words longer than the line width. We also need to
/// use `AsciiSpace` as the word separator since we need `' '`
/// characters between words in order to replace some of them with a
/// `'\n'`. Indentation is also ruled out. In other words,
/// `fill_inplace(width)` behaves as if you had called [`fill`] with
/// these options:
///
/// ```
/// # use textwrap::{core, LineEnding, Options, WordSplitter, WordSeparator, WrapAlgorithm};
/// # let width = 80;
/// Options {
/// width: width,
/// line_ending: LineEnding::LF,
/// initial_indent: "",
/// subsequent_indent: "",
/// break_words: false,
/// word_separator: WordSeparator::AsciiSpace,
/// wrap_algorithm: WrapAlgorithm::FirstFit,
/// word_splitter: WordSplitter::NoHyphenation,
/// };
/// Options::new(width)
/// .break_words(false)
/// .line_ending(LineEnding::LF)
/// .word_separator(WordSeparator::AsciiSpace)
/// .wrap_algorithm(WrapAlgorithm::FirstFit)
/// .word_splitter(WordSplitter::NoHyphenation);
/// ```
///
/// The wrap algorithm is [`WrapAlgorithm::FirstFit`] since this
Expand Down
34 changes: 34 additions & 0 deletions src/word_separators.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,40 @@ pub enum WordSeparator {
Custom(fn(line: &str) -> Box<dyn Iterator<Item = Word<'_>> + '_>),
}

impl PartialEq for WordSeparator {
/// Compare two word separators.
///
/// ```
/// use textwrap::WordSeparator;
///
/// assert_eq!(WordSeparator::AsciiSpace, WordSeparator::AsciiSpace);
/// #[cfg(feature = "unicode-linebreak")] {
/// assert_eq!(WordSeparator::UnicodeBreakProperties,
/// WordSeparator::UnicodeBreakProperties);
/// }
/// ```
///
/// Note that `WordSeparator::Custom` values never compare equal:
///
/// ```
/// use textwrap::WordSeparator;
/// use textwrap::core::Word;
/// fn word_separator(line: &str) -> Box<dyn Iterator<Item = Word<'_>> + '_> {
/// Box::new(line.split_inclusive(' ').map(Word::from))
/// }
/// assert_ne!(WordSeparator::Custom(word_separator),
/// WordSeparator::Custom(word_separator));
/// ```
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(WordSeparator::AsciiSpace, WordSeparator::AsciiSpace) => true,
#[cfg(feature = "unicode-linebreak")]
(WordSeparator::UnicodeBreakProperties, WordSeparator::UnicodeBreakProperties) => true,
(_, _) => false,
}
}
}

impl std::fmt::Debug for WordSeparator {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
30 changes: 30 additions & 0 deletions src/wrap_algorithms.rs
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,36 @@ pub enum WrapAlgorithm {
Custom(for<'a, 'b> fn(words: &'b [Word<'a>], line_widths: &'b [usize]) -> Vec<&'b [Word<'a>]>),
}

impl PartialEq for WrapAlgorithm {
/// Compare two wrap algorithms.
///
/// ```
/// use textwrap::WrapAlgorithm;
///
/// assert_eq!(WrapAlgorithm::FirstFit, WrapAlgorithm::FirstFit);
/// #[cfg(feature = "smawk")] {
/// assert_eq!(WrapAlgorithm::new_optimal_fit(), WrapAlgorithm::new_optimal_fit());
/// }
/// ```
///
/// Note that `WrapAlgorithm::Custom1` values never compare equal:
///
/// ```
/// use textwrap::WrapAlgorithm;
///
/// assert_ne!(WrapAlgorithm::Custom(|words, line_widths| vec![words]),
/// WrapAlgorithm::Custom(|words, line_widths| vec![words]));
/// ```
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(WrapAlgorithm::FirstFit, WrapAlgorithm::FirstFit) => true,
#[cfg(feature = "smawk")]
(WrapAlgorithm::OptimalFit(a), WrapAlgorithm::OptimalFit(b)) => a == b,
(_, _) => false,
}
}
}

impl std::fmt::Debug for WrapAlgorithm {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Expand Down
2 changes: 1 addition & 1 deletion src/wrap_algorithms/optimal_fit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ use crate::core::Fragment;
///
/// **Note:** Only available when the `smawk` Cargo feature is
/// enabled.
#[derive(Clone, Copy, Debug)]
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct Penalties {
/// Per-line penalty. This is added for every line, which makes it
/// expensive to output more lines than the minimum required.
Expand Down

0 comments on commit 0c9bbea

Please sign in to comment.