Skip to content

Commit

Permalink
refactor(di): reduce lifetime uses (#35)
Browse files Browse the repository at this point in the history
This tries to remove the `'a` lifetime from the generated container. However, 'impl Trait' inside the generic of managed types, when the 'impl Trait` itself is managed too, makes the complete removal of the lifetime impossible. This is because `impl Trait` cannot be used on struct fields. [So the struct field ends up having a reference](https://github.com/chesedo/despatma/blob/f69d18c7245f88a58d96e5919a5ee7181a6e8c4f/despatma-dependency-container/tests/expand/lifetime_with_managed_impl_trait_generic.expanded.rs#L25) which needs to have a lifetime.

This still reduces the use of the `'a` lifetime though.
  • Loading branch information
chesedo authored Nov 6, 2024
1 parent 4375589 commit 23c4929
Show file tree
Hide file tree
Showing 9 changed files with 242 additions and 20 deletions.
20 changes: 14 additions & 6 deletions .github/workflows/rust.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,23 +12,31 @@ env:
jobs:
fmt:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: dtolnay/[email protected]
with:
components: rustfmt
- name: Check format
run: bash scripts.sh cf

clippy:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: dtolnay/[email protected]
with:
components: clippy
- name: Clippy
run: bash scripts.sh cc

test:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v4
- uses: dtolnay/[email protected]
with:
components: rustfmt
- uses: cargo-bins/cargo-binstall@main
- name: Install cargo-expand
run: cargo binstall -y cargo-expand
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ struct Adder {
impl VisitMut for Adder {
fn visit_type_impl_trait_mut(&mut self, type_impl_trait: &mut TypeImplTrait) {
if self.to_add.contains(&type_impl_trait.bounds) {
type_impl_trait.bounds.push(parse_quote!('a));
type_impl_trait.bounds.push(parse_quote!(use<'a>));
} else {
// Continue checking for any impl types on inner generics
visit_type_impl_trait_mut(self, type_impl_trait);
Expand Down Expand Up @@ -144,11 +144,14 @@ mod tests {
assert_eq!(container.dependencies[2].borrow().ty, parse_quote!(Utc));
assert_eq!(
container.dependencies[3].borrow().ty,
parse_quote!(Presenter<impl Config + 'a>),
parse_quote!(Presenter<impl Config + use<'a>>),
);
#[rustfmt::skip]
assert_eq!(
container.dependencies[4].borrow().ty,
parse_quote!(Service<impl DAL + 'a, impl Config + 'a, Presenter<impl Config + 'a>>),
parse_quote!(
Service<impl DAL + use<'a>, impl Config + use<'a>, Presenter<impl Config + use<'a>>>
),
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,13 +14,8 @@ impl VisitorMut for WrapBoxType {
if dependency.is_boxed {
let ty = &dependency.ty;

if dependency.lifetime.is_managed() {
dependency.field_ty = parse_quote!(std::boxed::Box<#ty + 'a>);
dependency.ty = parse_quote!(std::boxed::Box<#ty + 'a>);
} else {
dependency.field_ty = parse_quote!(std::boxed::Box<#ty>);
dependency.ty = parse_quote!(std::boxed::Box<#ty>);
}
dependency.field_ty = parse_quote!(std::boxed::Box<#ty>);
dependency.ty = parse_quote!(std::boxed::Box<#ty>);
}
}
}
Expand Down Expand Up @@ -92,11 +87,11 @@ mod tests {

assert_eq!(
container.dependencies[0].borrow().ty,
parse_quote!(std::boxed::Box<dyn DAL + 'a>),
parse_quote!(std::boxed::Box<dyn DAL>),
);
assert_eq!(
container.dependencies[0].borrow().field_ty,
parse_quote!(std::boxed::Box<dyn DAL + 'a>)
parse_quote!(std::boxed::Box<dyn DAL>)
);
assert_eq!(
container.dependencies[1].borrow().ty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
use auto_impl::auto_impl;
trait DAL {}
const _: () = {
extern crate alloc;
impl<T: DAL + ?::core::marker::Sized> DAL for alloc::boxed::Box<T> {}
};
const _: () = {
impl<'a, T: 'a + DAL + ?::core::marker::Sized> DAL for &'a T {}
};
struct PostgresDAL;
impl DAL for PostgresDAL {}
struct SQLiteDAL;
impl DAL for SQLiteDAL {}
struct Service<D: DAL> {
dal: D,
}
impl<D: DAL> Service<D> {
fn new(dal: D) -> Self {
{
::std::io::_print(format_args!("Box dyn Trait singleton service started\n"));
};
Self { dal }
}
}
struct DependencyContainer<'a> {
dal: std::rc::Rc<std::cell::OnceCell<std::boxed::Box<dyn DAL>>>,
_phantom: std::marker::PhantomData<&'a ()>,
}
#[automatically_derived]
impl<'a> ::core::clone::Clone for DependencyContainer<'a> {
#[inline]
fn clone(&self) -> DependencyContainer<'a> {
DependencyContainer {
dal: ::core::clone::Clone::clone(&self.dal),
_phantom: ::core::clone::Clone::clone(&self._phantom),
}
}
}
impl<'a> DependencyContainer<'a> {
pub fn new() -> Self {
Self {
dal: Default::default(),
_phantom: Default::default(),
}
}
pub fn new_scope(&self) -> Self {
Self {
dal: self.dal.clone(),
_phantom: Default::default(),
}
}
pub fn dal(&'a self) -> &std::boxed::Box<dyn DAL> {
self.dal
.get_or_init(|| {
if true { Box::new(PostgresDAL) } else { Box::new(SQLiteDAL) }
})
}
pub fn service(&'a self) -> Service<&Box<dyn DAL>> {
let dal = self
.dal
.get_or_init(|| {
if true { Box::new(PostgresDAL) } else { Box::new(SQLiteDAL) }
});
Service::new(dal)
}
}
fn main() {
let container = DependencyContainer::new();
let _service = container.service();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
use auto_impl::auto_impl;

#[auto_impl(Box, &)]
trait DAL {}

struct PostgresDAL;

impl DAL for PostgresDAL {}

struct SQLiteDAL;

impl DAL for SQLiteDAL {}

struct Service<D: DAL> {
dal: D,
}

impl<D: DAL> Service<D> {
fn new(dal: D) -> Self {
println!("Box dyn Trait singleton service started");
Self { dal }
}
}

#[despatma_dependency_container::dependency_container]
impl DependencyContainer {
#[Singleton]
fn dal(&self) -> Box<dyn DAL> {
if true {
Box::new(PostgresDAL)
} else {
Box::new(SQLiteDAL)
}
}

fn service(&self, dal: &Box<dyn DAL>) -> Service<&Box<dyn DAL>> {
Service::new(dal)
}
}

fn main() {
let container = DependencyContainer::new();
let _service = container.service();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
use auto_impl::auto_impl;
trait DAL {}
const _: () = {
impl<'a, T: 'a + DAL + ?::core::marker::Sized> DAL for &'a T {}
};
struct PostgresDAL;
impl DAL for PostgresDAL {}
struct Service<D: DAL> {
dal: D,
}
impl<D: DAL> Service<D> {
fn new(dal: D) -> Self {
{
::std::io::_print(
format_args!(
"Lifetime service with managed impl trait generic started\n",
),
);
};
Self { dal }
}
}
struct DependencyContainer<'a> {
dal: std::rc::Rc<std::cell::OnceCell<PostgresDAL>>,
service: std::rc::Rc<std::cell::OnceCell<Service<&'a PostgresDAL>>>,
_phantom: std::marker::PhantomData<&'a ()>,
}
#[automatically_derived]
impl<'a> ::core::clone::Clone for DependencyContainer<'a> {
#[inline]
fn clone(&self) -> DependencyContainer<'a> {
DependencyContainer {
dal: ::core::clone::Clone::clone(&self.dal),
service: ::core::clone::Clone::clone(&self.service),
_phantom: ::core::clone::Clone::clone(&self._phantom),
}
}
}
impl<'a> DependencyContainer<'a> {
pub fn new() -> Self {
Self {
dal: Default::default(),
service: Default::default(),
_phantom: Default::default(),
}
}
pub fn new_scope(&self) -> Self {
Self {
dal: self.dal.clone(),
service: Default::default(),
_phantom: Default::default(),
}
}
pub fn dal(&'a self) -> &impl DAL {
self.dal.get_or_init(|| { PostgresDAL })
}
pub fn service(&'a self) -> &Service<impl DAL + use<'a>> {
let dal = self.dal.get_or_init(|| { PostgresDAL });
self.service.get_or_init(|| { Service::new(dal) })
}
}
fn main() {
let container = DependencyContainer::new();
let _service = container.service();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
use auto_impl::auto_impl;

#[auto_impl(&)]
trait DAL {}

struct PostgresDAL;

impl DAL for PostgresDAL {}

struct Service<D: DAL> {
dal: D,
}

impl<D: DAL> Service<D> {
fn new(dal: D) -> Self {
println!("Lifetime service with managed impl trait generic started",);
Self { dal }
}
}

#[despatma_dependency_container::dependency_container]
impl DependencyContainer {
#[Singleton(PostgresDAL)]
fn dal(&self) -> impl DAL {
PostgresDAL
}

#[Scoped]
fn service(&self, dal: impl DAL) -> Service<impl DAL> {
Service::new(dal)
}
}

fn main() {
let container = DependencyContainer::new();
let _service = container.service();
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ impl<'a> DependencyContainer<'a> {
if true { Box::new(PostgresDAL) } else { Box::new(SQLiteDAL) }
})
}
pub fn service(&'a self) -> Service<impl DAL + 'a> {
pub fn service(&'a self) -> Service<impl DAL + use<'a>> {
let config = Config { port: 8080 };
let dal = self
.dal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl<'a> DependencyContainer<'a> {
pub fn dal(&'a self) -> &impl DAL {
self.dal.get_or_init(|| { PostgresDAL })
}
pub fn service(&'a self) -> Service<impl DAL + 'a> {
pub fn service(&'a self) -> Service<impl DAL + use<'a>> {
let config = Config { port: 8080 };
let dal = self.dal.get_or_init(|| { PostgresDAL });
Service::new(config.port, dal)
Expand Down

0 comments on commit 23c4929

Please sign in to comment.