fix trait-solver issue requiring recursion_limit increase

Signed-off-by: Jason Volk <jason@zemos.net>
This commit is contained in:
Jason Volk 2024-10-03 22:03:39 +00:00 committed by strawberry
parent 2d049dacc3
commit bd9a9cc5f8
6 changed files with 37 additions and 17 deletions

View file

@ -1,5 +1,3 @@
#![recursion_limit = "192"]
pub mod client;
pub mod router;
pub mod server;

View file

@ -1,5 +1,3 @@
#![recursion_limit = "192"]
pub(crate) mod clap;
mod mods;
mod restart;

View file

@ -1,5 +1,3 @@
#![recursion_limit = "160"]
mod layers;
mod request;
mod router;

View file

@ -1,4 +1,3 @@
#![recursion_limit = "192"]
#![allow(refining_impl_trait)]
mod manager;

View file

@ -51,7 +51,7 @@ pub(crate) struct Args<'a> {
/// Dep is a reference to a service used within another service.
/// Circular-dependencies between services require this indirection.
pub(crate) struct Dep<T: Service> {
pub(crate) struct Dep<T: Service + Send + Sync> {
dep: OnceLock<Arc<T>>,
service: Weak<Map>,
name: &'static str,
@ -62,24 +62,47 @@ pub(crate) type MapType = BTreeMap<MapKey, MapVal>;
pub(crate) type MapVal = (Weak<dyn Service>, Weak<dyn Any + Send + Sync>);
pub(crate) type MapKey = String;
impl<T: Service> Deref for Dep<T> {
/// SAFETY: Workaround for a compiler limitation (or bug) where it is Hard to
/// prove the Sync'ness of Dep because services contain circular references
/// to other services through Dep's. The Sync'ness of Dep can still be
/// proved without unsafety by declaring the crate-attribute #![recursion_limit
/// = "192"] but this may take a while. Re-evaluate this when a new trait-solver
/// (such as Chalk) becomes available.
unsafe impl<T: Service> Sync for Dep<T> {}
/// SAFETY: Ancillary to unsafe impl Sync; while this is not needed to prevent
/// violating the recursion_limit, the trait-solver still spends an inordinate
/// amount of time to prove this.
unsafe impl<T: Service> Send for Dep<T> {}
impl<T: Service + Send + Sync> Deref for Dep<T> {
type Target = Arc<T>;
/// Dereference a dependency. The dependency must be ready or panics.
#[inline]
fn deref(&self) -> &Self::Target {
self.dep.get_or_init(|| {
let service = self
.service
.upgrade()
.expect("services map exists for dependency initialization.");
self.dep.get_or_init(
#[inline(never)]
|| self.init(),
)
}
}
require::<T>(&service, self.name)
})
impl<T: Service + Send + Sync> Dep<T> {
#[inline]
fn init(&self) -> Arc<T> {
let service = self
.service
.upgrade()
.expect("services map exists for dependency initialization.");
require::<T>(&service, self.name)
}
}
impl<'a> Args<'a> {
/// Create a lazy-reference to a service when constructing another Service.
#[inline]
pub(crate) fn depend<T: Service>(&'a self, name: &'static str) -> Dep<T> {
Dep::<T> {
dep: OnceLock::new(),
@ -90,12 +113,14 @@ impl<'a> Args<'a> {
/// Create a reference immediately to a service when constructing another
/// Service. The other service must be constructed.
#[inline]
pub(crate) fn require<T: Service>(&'a self, name: &str) -> Arc<T> { require::<T>(self.service, name) }
}
/// Reference a Service by name. Panics if the Service does not exist or was
/// incorrectly cast.
pub(crate) fn require<T: Service>(map: &Map, name: &str) -> Arc<T> {
#[inline]
fn require<T: Service>(map: &Map, name: &str) -> Arc<T> {
try_get::<T>(map, name)
.inspect_err(inspect_log)
.expect("Failure to reference service required by another service.")

View file

@ -195,6 +195,7 @@ impl Services {
}
}
#[inline]
pub fn try_get<T>(&self, name: &str) -> Result<Arc<T>>
where
T: Any + Send + Sync + Sized,
@ -202,6 +203,7 @@ impl Services {
service::try_get::<T>(&self.service, name)
}
#[inline]
pub fn get<T>(&self, name: &str) -> Option<Arc<T>>
where
T: Any + Send + Sync + Sized,