use futures::{future::Shared, Future, FutureExt}; use rustc_hash::FxHashMap; use unic_langid::LanguageIdentifier;
pubtype RcResource = Rc<FluentResource>;
/// An option type whose None variant is either optional or required. /// /// This behaves similarly to the standard-library [`Option`] type /// except that there are two [`None`]-like variants: /// [`ResourceOption::MissingOptional`] and [`ResourceOption::MissingRequired`]. #[derive(Clone, Debug)] pubenum ResourceOption { /// An available resource.
Some(RcResource), /// A missing optional resource.
MissingOptional, /// A missing required resource.
MissingRequired,
}
impl ResourceOption { /// Creates a resource option that is either [`ResourceOption::MissingRequired`] /// or [`ResourceOption::MissingOptional`] based on whether the given [`ResourceId`] /// is required or optional. pubfn missing_resource(resource_id: &ResourceId) -> Self { if resource_id.is_required() { Self::MissingRequired
} else { Self::MissingOptional
}
}
/// Returns [`true`] if this option contains a recource, otherwise [`false`]. pubfn is_some(&self) -> bool {
matches!(self, Self::Some(_))
}
/// Resource [`true`] if this option is missing a resource of any type, otherwise [`false`]. pubfn is_none(&self) -> bool {
matches!(self, Self::MissingOptional | Self::MissingRequired)
}
/// Returns [`true`] if this option is missing a required resource, otherwise [`false`]. pubfn is_required_and_missing(&self) -> bool {
matches!(self, Self::MissingRequired)
}
}
impl From<ResourceOption> for Option<RcResource> { fn from(other: ResourceOption) -> Self { match other {
ResourceOption::Some(id) => Some(id),
_ => None,
}
}
}
#[derive(Debug, Clone)] pubenum ResourceStatus { /// The resource is missing. Don't bother trying to fetch.
MissingRequired,
MissingOptional, /// The resource is loading and future will deliver the result.
Loading(ResourceFuture), /// The resource is loaded and parsed.
Loaded(RcResource),
}
match this {
MissingRequired => ResourceOption::MissingRequired.into(),
MissingOptional => ResourceOption::MissingOptional.into(),
Loaded(res) => ResourceOption::Some(res.clone()).into(),
Loading(res) => Pin::new(res).poll(cx),
}
}
}
/// `FileSource` provides a generic fetching and caching of fluent resources. /// The user of `FileSource` provides a [`FileFetcher`](trait.FileFetcher.html) /// implementation and `FileSource` takes care of the rest. #[derive(Clone)] pubstruct FileSource { /// Name of the FileSource, e.g. "browser" pub name: String, /// Pre-formatted path for the FileSource, e.g. "/browser/data/locale/{locale}/" pub pre_path: String, /// Metasource name for the FileSource, e.g. "app", "langpack" /// Only sources from the same metasource are passed into the solver. pub metasource: String, /// The locales for which data is present in the FileSource, e.g. ["en-US", "pl"]
locales: Vec<LanguageIdentifier>,
shared: Rc<Inner>,
index: Option<Vec<String>>, pub options: FileSourceOptions,
}
/// Attempt to synchronously fetch resource for the combination of `locale` /// and `path`. Returns `Some(ResourceResult)` if the resource is available, /// else `None`. pubfn fetch_file_sync(
&self,
locale: &LanguageIdentifier,
resource_id: &ResourceId,
overload: bool,
) -> ResourceOption { use ResourceStatus::*;
let full_path_id = self
.get_path(locale, resource_id)
.to_resource_id(resource_id.resource_type);
let res = self.shared.lookup_resource(full_path_id.clone(), || { self.fetch_sync(&full_path_id).into()
});
match res {
MissingRequired => ResourceOption::MissingRequired,
MissingOptional => ResourceOption::MissingOptional,
Loaded(res) => ResourceOption::Some(res),
Loading(..) if overload => { // A sync load has been requested for the same resource that has // a pending async load in progress. How do we handle this? // // Ideally, we would sync load and resolve all the pending // futures with the result. With the current Futures and // combinators, it's unclear how to proceed. One potential // solution is to store a oneshot::Sender and // Shared<oneshot::Receiver>. When the async loading future // resolves it would check that the state is still `Loading`, // and if so, send the result. The sync load would do the same // send on the oneshot::Sender. // // For now, we warn and return the resource, paying the cost of // duplication of the resource. self.fetch_sync(&full_path_id)
}
Loading(..) => {
panic!("[l10nregistry] Attempting to synchronously load file {} while it's being loaded asynchronously.", &full_path_id.value);
}
}
}
/// Attempt to fetch resource for the combination of `locale` and `path`. /// Returns [`ResourceStatus`](enum.ResourceStatus.html) which is /// a `Future` that can be polled. pubfn fetch_file(
&self,
locale: &LanguageIdentifier,
resource_id: &ResourceId,
) -> ResourceStatus { use ResourceStatus::*;
/// Determine if the `FileSource` has a loaded resource for the combination /// of `locale` and `path`. Returns `Some(true)` if the file is loaded, else /// `Some(false)`. `None` is returned if there is an outstanding async fetch /// pending and the status is yet to be determined. pubfn has_file<L: Borrow<LanguageIdentifier>>(
&self,
locale: L,
path: &ResourceId,
) -> Option<bool> { let locale = locale.borrow(); if !self.locales.contains(locale) {
Some(false)
} else { let full_path = self.get_path(locale, path); iflet Some(index) = &self.index { return Some(index.iter().any(|p| p == &full_path));
} self.shared.has_file(&full_path)
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.