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 client;
pub mod router; pub mod router;
pub mod server; pub mod server;

View file

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

View file

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

View file

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

View file

@ -51,7 +51,7 @@ pub(crate) struct Args<'a> {
/// Dep is a reference to a service used within another service. /// Dep is a reference to a service used within another service.
/// Circular-dependencies between services require this indirection. /// 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>>, dep: OnceLock<Arc<T>>,
service: Weak<Map>, service: Weak<Map>,
name: &'static str, 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 MapVal = (Weak<dyn Service>, Weak<dyn Any + Send + Sync>);
pub(crate) type MapKey = String; 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>; type Target = Arc<T>;
/// Dereference a dependency. The dependency must be ready or panics. /// Dereference a dependency. The dependency must be ready or panics.
#[inline]
fn deref(&self) -> &Self::Target { fn deref(&self) -> &Self::Target {
self.dep.get_or_init(|| { self.dep.get_or_init(
let service = self #[inline(never)]
.service || self.init(),
.upgrade() )
.expect("services map exists for dependency initialization."); }
}
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> { impl<'a> Args<'a> {
/// Create a lazy-reference to a service when constructing another Service. /// 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> { pub(crate) fn depend<T: Service>(&'a self, name: &'static str) -> Dep<T> {
Dep::<T> { Dep::<T> {
dep: OnceLock::new(), dep: OnceLock::new(),
@ -90,12 +113,14 @@ impl<'a> Args<'a> {
/// Create a reference immediately to a service when constructing another /// Create a reference immediately to a service when constructing another
/// Service. The other service must be constructed. /// 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) } 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 /// Reference a Service by name. Panics if the Service does not exist or was
/// incorrectly cast. /// 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) try_get::<T>(map, name)
.inspect_err(inspect_log) .inspect_err(inspect_log)
.expect("Failure to reference service required by another service.") .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>> pub fn try_get<T>(&self, name: &str) -> Result<Arc<T>>
where where
T: Any + Send + Sync + Sized, T: Any + Send + Sync + Sized,
@ -202,6 +203,7 @@ impl Services {
service::try_get::<T>(&self.service, name) service::try_get::<T>(&self.service, name)
} }
#[inline]
pub fn get<T>(&self, name: &str) -> Option<Arc<T>> pub fn get<T>(&self, name: &str) -> Option<Arc<T>>
where where
T: Any + Send + Sync + Sized, T: Any + Send + Sync + Sized,