use std::{
pin::Pin,
task::{Context, Poll},
};
use crate::{
env::ErrorReporter,
errors::{L10nRegistryError, L10nRegistrySetupError},
fluent::{FluentBundle, FluentError},
registry::{BundleAdapter, L10nRegistry, MetaSources},
solver::{AsyncTester, ParallelProblemSolver},
source::{ResourceOption, ResourceStatus},
};
use fluent_fallback::{generator::BundleStream, types::ResourceId};
use futures::{
stream::{Collect, FuturesOrdered},
Stream, StreamExt,
};
use std::future::Future;
use unic_langid::LanguageIdentifier;
impl
L10nRegistry
where
P: Clone,
B: Clone,
{
/// This method is useful for testing various configurations.
#[cfg(feature = "test-fluent")]
pub fn generate_bundles_for_lang(
&self,
langid: LanguageIdentifier,
resource_ids: Vec,
) -> Result, L10nRegistrySetupError> {
let lang_ids = vec![langid];
Ok(GenerateBundles::new(
self.clone(),
lang_ids.into_iter(),
resource_ids,
// Cheaply create an immutable shallow copy of the [MetaSources].
self.try_borrow_metasources()?.clone(),
))
}
// Asynchronously generate the bundles.
pub fn generate_bundles(
&self,
locales: std::vec::IntoIter,
resource_ids: Vec,
) -> Result, L10nRegistrySetupError> {
Ok(GenerateBundles::new(
self.clone(),
locales,
resource_ids,
// Cheaply create an immutable shallow copy of the [MetaSources].
self.try_borrow_metasources()?.clone(),
))
}
}
/// This enum contains the various states the [GenerateBundles] can be in during the
/// asynchronous generation step.
enum State
{
fn get_locale(&self) -> &LanguageIdentifier {
match self {
Self::Locale(locale) => locale,
Self::Solver { locale, .. } => locale,
Self::Empty => unreachable!("Attempting to get a locale for an empty state."),
}
}
fn take_solver(&mut self) -> ParallelProblemSolver> {
replace_with::replace_with_or_default_and_return(self, |self_| match self_ {
Self::Solver { locale, solver } => (solver, Self::Locale(locale)),
_ => unreachable!("Attempting to take a solver in an invalid state."),
})
}
fn put_back_solver(&mut self, solver: ParallelProblemSolver>) {
replace_with::replace_with_or_default(self, |self_| match self_ {
Self::Locale(locale) => Self::Solver { locale, solver },
_ => unreachable!("Attempting to put back a solver in an invalid state."),
})
}
}
pub struct GenerateBundles
{
/// Do not access the metasources in the registry, as they may be mutated between
/// async iterations.
reg: L10nRegistry
,
/// This is an immutable shallow copy of the MetaSources that should not be mutated
/// during the iteration process. This ensures that the iterator will still be
/// valid if the L10nRegistry is mutated while iterating through the sources.
metasources: MetaSources,
locales: std::vec::IntoIter,
current_metasource: usize,
resource_ids: Vec,
state: State
where
P: ErrorReporter,
B: BundleAdapter,
{
type Item = Result)>;
/// Asynchronously try and get a solver, and then with the solver generate a bundle.
/// If the solver is not ready yet, then this function will return as `Pending`, and
/// the Future runner will need to re-enter at a later point to try again.
fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll