diff options
Diffstat (limited to 'intl/l10n/rust/l10nregistry-rs/src/solver/parallel.rs')
-rw-r--r-- | intl/l10n/rust/l10nregistry-rs/src/solver/parallel.rs | 175 |
1 files changed, 175 insertions, 0 deletions
diff --git a/intl/l10n/rust/l10nregistry-rs/src/solver/parallel.rs b/intl/l10n/rust/l10nregistry-rs/src/solver/parallel.rs new file mode 100644 index 0000000000..320ad65c89 --- /dev/null +++ b/intl/l10n/rust/l10nregistry-rs/src/solver/parallel.rs @@ -0,0 +1,175 @@ +use super::ProblemSolver; +use std::ops::{Deref, DerefMut}; + +use futures::ready; +use std::future::Future; +use std::pin::Pin; + +pub trait AsyncTester { + type Result: Future<Output = Vec<bool>>; + + fn test_async(&self, query: Vec<(usize, usize)>) -> Self::Result; +} + +pub struct ParallelProblemSolver<T> +where + T: AsyncTester, +{ + solver: ProblemSolver, + current_test: Option<(T::Result, Vec<usize>)>, +} + +impl<T: AsyncTester> Deref for ParallelProblemSolver<T> { + type Target = ProblemSolver; + + fn deref(&self) -> &Self::Target { + &self.solver + } +} + +impl<T: AsyncTester> DerefMut for ParallelProblemSolver<T> { + fn deref_mut(&mut self) -> &mut Self::Target { + &mut self.solver + } +} + +impl<T: AsyncTester> ParallelProblemSolver<T> { + pub fn new(width: usize, depth: usize) -> Self { + Self { + solver: ProblemSolver::new(width, depth), + current_test: None, + } + } +} + +type TestQuery = (Vec<(usize, usize)>, Vec<usize>); + +impl<T: AsyncTester> ParallelProblemSolver<T> { + pub fn try_generate_complete_candidate(&mut self) -> bool { + while !self.is_complete() { + while self.is_current_cell_missing() { + if !self.try_advance_source() { + return false; + } + } + if !self.try_advance_resource() { + return false; + } + } + true + } + + fn try_generate_test_query(&mut self) -> Result<TestQuery, usize> { + let mut test_cells = vec![]; + let query = self + .solution + .iter() + .enumerate() + .filter_map(|(res_idx, source_idx)| { + let cell = self.cache[res_idx][*source_idx]; + match cell { + None => { + test_cells.push(res_idx); + Some(Ok((res_idx, *source_idx))) + } + Some(false) => Some(Err(res_idx)), + Some(true) => None, + } + }) + .collect::<Result<_, _>>()?; + Ok((query, test_cells)) + } + + fn apply_test_result( + &mut self, + resources: Vec<bool>, + testing_cells: Vec<usize>, + ) -> Result<(), usize> { + let mut first_missing = None; + for (result, res_idx) in resources.into_iter().zip(testing_cells) { + let source_idx = self.solution[res_idx]; + self.cache[res_idx][source_idx] = Some(result); + if !result && first_missing.is_none() { + first_missing = Some(res_idx); + } + } + if let Some(idx) = first_missing { + Err(idx) + } else { + Ok(()) + } + } + + pub fn try_poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + tester: &T, + prefetch: bool, + ) -> std::task::Poll<Result<Option<Vec<usize>>, usize>> + where + <T as AsyncTester>::Result: Unpin, + { + if self.width == 0 || self.depth == 0 { + return Ok(None).into(); + } + + 'outer: loop { + if let Some((test, testing_cells)) = &mut self.current_test { + let pinned = Pin::new(test); + let set = ready!(pinned.poll(cx)); + let testing_cells = testing_cells.clone(); + + if let Err(res_idx) = self.apply_test_result(set, testing_cells) { + self.idx = res_idx; + self.prune(); + if !self.bail() { + if let Some(res_idx) = self.has_missing_cell() { + return Err(res_idx).into(); + } else { + return Ok(None).into(); + } + } + self.current_test = None; + continue 'outer; + } else { + self.current_test = None; + if !prefetch { + self.dirty = true; + } + return Ok(Some(self.solution.clone())).into(); + } + } else { + if self.dirty { + if !self.bail() { + if let Some(res_idx) = self.has_missing_cell() { + return Err(res_idx).into(); + } else { + return Ok(None).into(); + } + } + self.dirty = false; + } + while self.try_generate_complete_candidate() { + match self.try_generate_test_query() { + Ok((query, testing_cells)) => { + self.current_test = Some((tester.test_async(query), testing_cells)); + continue 'outer; + } + Err(res_idx) => { + self.idx = res_idx; + self.prune(); + if !self.bail() { + if let Some(res_idx) = self.has_missing_cell() { + return Err(res_idx).into(); + } else { + return Ok(None).into(); + } + } + } + } + } + return Ok(None).into(); + } + } + } +} |