Skip to content

Commit

Permalink
[para-api] Convert compute_initial_info to use an Option outparam
Browse files Browse the repository at this point in the history
  • Loading branch information
jfkthame committed Dec 6, 2023
1 parent c26bd19 commit 5d785ce
Show file tree
Hide file tree
Showing 2 changed files with 47 additions and 50 deletions.
79 changes: 35 additions & 44 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -264,51 +264,49 @@ impl<'text> InitialInfoExt<'text> {
text: &'a str,
default_para_level: Option<Level>,
) -> InitialInfoExt<'a> {
let (original_classes, paragraphs, pure_ltr, _, _) =
compute_initial_info(data_source, text, default_para_level, true);
let mut paragraphs = Vec::<ParagraphInfo>::new();
let mut pure_ltr = Vec::<bool>::new();
let (original_classes, _, _) = compute_initial_info(
data_source,
text,
default_para_level,
Some((&mut paragraphs, &mut pure_ltr)),
);

InitialInfoExt {
base: InitialInfo {
text,
original_classes,
paragraphs: paragraphs.unwrap(),
paragraphs,
},
pure_ltr: pure_ltr.unwrap(),
pure_ltr,
}
}
}

/// Implementation of initial-info computation.
/// This is used for both BidiInfo and ParagraphBidiInfo, with split_paragraphs=true
/// indicating that it should split paragraphs and return the two Option<> results
/// (for BidiInfo), and split_paragraphs=false indicating it should not split paras,
/// and returns the single paragraph_level and is_pure_ltr values instead.
/// Implementation of initial-info computation for both BidiInfo and ParagraphBidiInfo.
/// To treat the text as (potentially) multiple paragraphs, the caller should pass the
/// pair of optional outparam arrays to receive the ParagraphInfo and pure-ltr flags
/// for each paragraph. Passing None for split_paragraphs will ignore any paragraph-
/// separator characters in the text, treating it just as a single paragraph.
/// Returns the array of BidiClass values for each code unit of the text, along with
/// the embedding level and pure-ltr flag for the *last* (or only) paragraph.
fn compute_initial_info<'a, D: BidiDataSource, T: TextSource<'a> + ?Sized>(
data_source: &D,
text: &'a T,
default_para_level: Option<Level>,
split_paragraphs: bool,
) -> (
Vec<BidiClass>,
Option<Vec<ParagraphInfo>>,
Option<Vec<bool>>,
Level,
bool,
) {
mut split_paragraphs: Option<(&mut Vec<ParagraphInfo>, &mut Vec<bool>)>,
) -> (Vec<BidiClass>, Level, bool) {
let mut original_classes = Vec::with_capacity(text.len());

// The stack contains the starting code unit index for each nested isolate we're inside.
let mut isolate_stack = Vec::new();
let mut paragraphs = if split_paragraphs {
Some(Vec::new())
} else {
None
};
let mut pure_ltr = if split_paragraphs {
Some(Vec::new())
} else {
None
};

#[cfg(debug_assertions)]

Check failure on line 305 in src/lib.rs

View workflow job for this annotation

GitHub Actions / Test (ubuntu-latest, 1.36.0)

attributes are not yet allowed on `if` expressions
if let Some((ref paragraphs, ref pure_ltr)) = split_paragraphs {
debug_assert!(paragraphs.is_empty());
debug_assert!(pure_ltr.is_empty());
}

let mut para_start = 0;
let mut para_level = default_para_level;
Expand All @@ -334,16 +332,16 @@ fn compute_initial_info<'a, D: BidiDataSource, T: TextSource<'a> + ?Sized>(

match class {
B => {
if split_paragraphs {
if let Some((ref mut paragraphs, ref mut pure_ltr)) = split_paragraphs {
// P1. Split the text into separate paragraphs. The paragraph separator is kept
// with the previous paragraph.
let para_end = i + len;
paragraphs.as_mut().unwrap().push(ParagraphInfo {
paragraphs.push(ParagraphInfo {
range: para_start..para_end,
// P3. If no character is found in p2, set the paragraph level to zero.
level: para_level.unwrap_or(LTR_LEVEL),
});
pure_ltr.as_mut().unwrap().push(is_pure_ltr);
pure_ltr.push(is_pure_ltr);
// Reset state for the start of the next paragraph.
para_start = para_end;
// TODO: Support defaulting to direction of previous paragraph
Expand All @@ -352,8 +350,6 @@ fn compute_initial_info<'a, D: BidiDataSource, T: TextSource<'a> + ?Sized>(
para_level = default_para_level;
is_pure_ltr = true;
isolate_stack.clear();
} else {
// XXX Is there anything we should do here?
}
}

Expand Down Expand Up @@ -400,28 +396,23 @@ fn compute_initial_info<'a, D: BidiDataSource, T: TextSource<'a> + ?Sized>(
}
}

if split_paragraphs {
if let Some((paragraphs, pure_ltr)) = split_paragraphs {
if para_start < text.len() {
paragraphs.as_mut().unwrap().push(ParagraphInfo {
paragraphs.push(ParagraphInfo {
range: para_start..text.len(),
level: para_level.unwrap_or(LTR_LEVEL),
});
pure_ltr.as_mut().unwrap().push(is_pure_ltr);
pure_ltr.push(is_pure_ltr);
}
assert_eq!(
paragraphs.as_ref().unwrap().len(),
pure_ltr.as_ref().unwrap().len()
);
debug_assert_eq!(paragraphs.len(), pure_ltr.len());
}
assert_eq!(original_classes.len(), text.len());
debug_assert_eq!(original_classes.len(), text.len());

#[cfg(feature = "flame_it")]
flame::end("compute_initial_info(): iter text.char_indices()");

(
original_classes,
paragraphs,
pure_ltr,
para_level.unwrap_or(LTR_LEVEL),
is_pure_ltr,
)
Expand Down Expand Up @@ -720,8 +711,8 @@ impl<'text> ParagraphBidiInfo<'text> {
) -> ParagraphBidiInfo<'a> {
// Here we could create a ParagraphInitialInfo struct to parallel the one
// used by BidiInfo, but there doesn't seem any compelling reason for it.
let (original_classes, _, _, paragraph_level, is_pure_ltr) =
compute_initial_info(data_source, text, default_para_level, false);
let (original_classes, paragraph_level, is_pure_ltr) =
compute_initial_info(data_source, text, default_para_level, None);

let mut levels = Vec::<Level>::with_capacity(text.len());
let mut processing_classes = original_classes.clone();
Expand Down
18 changes: 12 additions & 6 deletions src/utf16.rs
Original file line number Diff line number Diff line change
Expand Up @@ -102,16 +102,22 @@ impl<'text> InitialInfoExt<'text> {
text: &'a [u16],
default_para_level: Option<Level>,
) -> InitialInfoExt<'a> {
let (original_classes, paragraphs, pure_ltr, _, _) =
compute_initial_info(data_source, text, default_para_level, true);
let mut paragraphs = Vec::<ParagraphInfo>::new();
let mut pure_ltr = Vec::<bool>::new();
let (original_classes, _, _) = compute_initial_info(
data_source,
text,
default_para_level,
Some((&mut paragraphs, &mut pure_ltr)),
);

InitialInfoExt {
base: InitialInfo {
text,
original_classes,
paragraphs: paragraphs.unwrap(),
paragraphs,
},
pure_ltr: pure_ltr.unwrap(),
pure_ltr,
}
}
}
Expand Down Expand Up @@ -405,8 +411,8 @@ impl<'text> ParagraphBidiInfo<'text> {
) -> ParagraphBidiInfo<'a> {
// Here we could create a ParagraphInitialInfo struct to parallel the one
// used by BidiInfo, but there doesn't seem any compelling reason for it.
let (original_classes, _, _, paragraph_level, is_pure_ltr) =
compute_initial_info(data_source, text, default_para_level, false);
let (original_classes, paragraph_level, is_pure_ltr) =
compute_initial_info(data_source, text, default_para_level, None);

let mut levels = Vec::<Level>::with_capacity(text.len());
let mut processing_classes = original_classes.clone();
Expand Down

0 comments on commit 5d785ce

Please sign in to comment.