From eb9852a047e5fa7e6d6859b9575b462b42fefd62 Mon Sep 17 00:00:00 2001
From: Joseph Walton-Rivers <joseph@walton-rivers.uk>
Date: Sat, 25 Mar 2023 12:18:42 +0000
Subject: [PATCH] use concepts for module system

---
 CMakeLists.txt                                |  4 +-
 demo/CMakeLists.txt                           |  4 +
 fggl/assets/module.cpp                        |  2 +-
 fggl/assets/packed/module.cpp                 |  2 +-
 fggl/audio/fallback/audio.cpp                 |  2 +-
 fggl/audio/openal/module.cpp                  |  2 +-
 fggl/data/assimp/module.cpp                   |  2 +-
 fggl/data/module.cpp                          |  2 +-
 fggl/entity/module.cpp                        |  2 +-
 fggl/gfx/ogl4/module.cpp                      |  2 +-
 fggl/phys/null.cpp                            |  2 +-
 include/fggl/assets/loader.hpp                |  2 +-
 include/fggl/assets/manager.hpp               |  2 +-
 include/fggl/assets/module.hpp                |  6 +-
 include/fggl/assets/packed/adapter.hpp        |  2 +-
 include/fggl/assets/packed/direct.hpp         |  2 +-
 include/fggl/assets/packed/module.hpp         |  6 +-
 include/fggl/audio/audio.hpp                  |  4 +-
 include/fggl/audio/null_audio.hpp             |  6 +-
 include/fggl/audio/openal/module.hpp          |  6 +-
 include/fggl/data/assimp/module.hpp           |  6 +-
 include/fggl/data/module.hpp                  |  6 +-
 include/fggl/data/storage.hpp                 |  4 +-
 include/fggl/display/glfw/module.hpp          |  8 +-
 include/fggl/display/window.hpp               |  2 +-
 include/fggl/entity/loader/loader.hpp         |  2 +-
 include/fggl/entity/module.hpp                |  6 +-
 include/fggl/gfx/interfaces.hpp               |  2 +-
 include/fggl/gfx/ogl4/module.hpp              |  6 +-
 include/fggl/gfx/setup.hpp                    |  2 +-
 include/fggl/gui/fonts.hpp                    |  2 +-
 include/fggl/gui/module.hpp                   |  8 +-
 include/fggl/input/input.hpp                  |  4 +-
 include/fggl/input/module.hpp                 |  8 +-
 include/fggl/modules/manager.hpp              | 29 ++++++-
 include/fggl/modules/module.hpp               | 60 ++++++---------
 include/fggl/modules/service.hpp              | 75 +++++++++++++++++++
 include/fggl/phys/null.hpp                    |  6 +-
 include/fggl/phys/service.hpp                 |  2 +-
 include/fggl/script/engine.hpp                |  2 +-
 .../lua/include/fggl/script/lua/module.hpp    |  6 +-
 integrations/lua/src/module.cpp               |  4 +-
 42 files changed, 199 insertions(+), 113 deletions(-)
 create mode 100644 include/fggl/modules/service.hpp

diff --git a/CMakeLists.txt b/CMakeLists.txt
index 5a9e2c4..1c7eb76 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -82,9 +82,7 @@ endif()
 
 # Demo project
 if (FGGL_EXAMPLES)
-	add_subdirectory(demo)
-	target_compile_options( demo PRIVATE -Wall -Wextra -Wodr -Wdouble-promotion -fno-strict-aliasing -fno-strict-overflow )
-	set_property(TARGET demo PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
+	add_subdirectory(demo EXCLUDE_FROM_ALL)
 endif()
 
 ##
diff --git a/demo/CMakeLists.txt b/demo/CMakeLists.txt
index 62fc663..665ed51 100644
--- a/demo/CMakeLists.txt
+++ b/demo/CMakeLists.txt
@@ -14,6 +14,10 @@ add_executable(demo
         demo/hexboard/camera.cpp
 )
 
+# set build flags
+target_compile_options( demo PRIVATE -Wall -Wextra -Wodr -Wdouble-promotion -fno-strict-aliasing -fno-strict-overflow )
+set_property(TARGET demo PROPERTY INTERPROCEDURAL_OPTIMIZATION True)
+
 target_include_directories(demo
         PRIVATE
             ${CMAKE_CURRENT_SOURCE_DIR}/include
diff --git a/fggl/assets/module.cpp b/fggl/assets/module.cpp
index 5532515..6700299 100644
--- a/fggl/assets/module.cpp
+++ b/fggl/assets/module.cpp
@@ -20,7 +20,7 @@
 
 namespace fggl::assets {
 
-	auto AssetFolders::factory(modules::ModuleService service, modules::Services &services) -> bool {
+	auto AssetFolders::factory(modules::ServiceName service, modules::Services &services) -> bool {
 		if (service == Loader::service) {
 			auto *storage = services.get<data::Storage>();
 			auto *checkin = services.get<CheckinAdapted>();
diff --git a/fggl/assets/packed/module.cpp b/fggl/assets/packed/module.cpp
index 44e9e56..4d9dc9e 100644
--- a/fggl/assets/packed/module.cpp
+++ b/fggl/assets/packed/module.cpp
@@ -20,7 +20,7 @@
 
 namespace fggl::assets {
 
-	auto PackedAssets::factory(modules::ModuleService service, modules::Services &services) -> bool {
+	auto PackedAssets::factory(modules::ServiceName service, modules::Services &services) -> bool {
 		if (service == RawCheckin::service) {
 			services.create<RawCheckin>();
 			return true;
diff --git a/fggl/audio/fallback/audio.cpp b/fggl/audio/fallback/audio.cpp
index 50edca4..32dd285 100644
--- a/fggl/audio/fallback/audio.cpp
+++ b/fggl/audio/fallback/audio.cpp
@@ -26,7 +26,7 @@ namespace fggl::audio {
 	void NullAudioService::play(const fggl::audio::AudioClipShort &, bool) {
 	}
 
-	auto NullAudio::factory(modules::ModuleService service, modules::Services &services) -> bool{
+	auto NullAudio::factory(modules::ServiceName service, modules::Services &services) -> bool{
 		if (service == SERVICE_AUDIO_PLAYBACK) {
 			services.bind<audio::AudioService, audio::NullAudioService>();
 			return true;
diff --git a/fggl/audio/openal/module.cpp b/fggl/audio/openal/module.cpp
index 909dc63..843cd42 100644
--- a/fggl/audio/openal/module.cpp
+++ b/fggl/audio/openal/module.cpp
@@ -20,7 +20,7 @@
 
 namespace fggl::audio {
 
-	auto OpenAL::factory(modules::ModuleService service, modules::Services &services) -> bool {
+	auto OpenAL::factory(modules::ServiceName service, modules::Services &services) -> bool {
 		if (service == SERVICE_AUDIO_PLAYBACK) {
 			auto* assets = services.get<assets::AssetManager>();
 
diff --git a/fggl/data/assimp/module.cpp b/fggl/data/assimp/module.cpp
index d7852e2..453edfb 100644
--- a/fggl/data/assimp/module.cpp
+++ b/fggl/data/assimp/module.cpp
@@ -314,7 +314,7 @@ namespace fggl::data::models {
 		return true;
 	}
 
-	auto AssimpModule::factory(modules::ModuleService service, modules::Services &serviceManager) -> bool {
+	auto AssimpModule::factory(modules::ServiceName service, modules::Services &serviceManager) -> bool {
 		if ( service == MODEL_PROVIDER ) {
 			auto* assetLoader = serviceManager.get<assets::Loader>();
 			assetLoader->setFactory( MODEL_MULTI3D, load_assimp_model, assets::LoadType::PATH );
diff --git a/fggl/data/module.cpp b/fggl/data/module.cpp
index 1872b5f..cbf9127 100644
--- a/fggl/data/module.cpp
+++ b/fggl/data/module.cpp
@@ -20,7 +20,7 @@
 
 namespace fggl::data {
 
-	auto LocalStorage::factory(modules::ModuleService service, modules::Services &data) -> bool {
+	auto LocalStorage::factory(modules::ServiceName service, modules::Services &data) -> bool {
 		if (service == SERVICE_STORAGE) {
 			// FIXME: no easy way to set the application name
 			auto pathConfig = fggl::platform::calc_engine_paths("fggl-demo");
diff --git a/fggl/entity/module.cpp b/fggl/entity/module.cpp
index 29256f5..1168872 100644
--- a/fggl/entity/module.cpp
+++ b/fggl/entity/module.cpp
@@ -65,7 +65,7 @@ namespace fggl::entity {
 	}
 
 
-	auto ECS::factory(modules::ModuleService service, modules::Services &services) -> bool {
+	auto ECS::factory(modules::ServiceName service, modules::Services &services) -> bool {
 		if (service == EntityFactory::service) {
 			auto *factory = services.create<EntityFactory>(services);
 			install_component_factories(factory);
diff --git a/fggl/gfx/ogl4/module.cpp b/fggl/gfx/ogl4/module.cpp
index 8757be7..14974f1 100644
--- a/fggl/gfx/ogl4/module.cpp
+++ b/fggl/gfx/ogl4/module.cpp
@@ -169,7 +169,7 @@ namespace fggl::gfx {
 		light.quadratic = spec.get<float>("quadratic", 0.000007F);
 	}
 
-	auto OpenGL4::factory(modules::ModuleService service, modules::Services &services) -> bool {
+	auto OpenGL4::factory(modules::ServiceName service, modules::Services &services) -> bool {
 		if (service == WindowGraphics::service) {
 			// setup the thing responsible for graphics
 			auto *storage = services.get<data::Storage>();
diff --git a/fggl/phys/null.cpp b/fggl/phys/null.cpp
index e993987..9df68b2 100644
--- a/fggl/phys/null.cpp
+++ b/fggl/phys/null.cpp
@@ -20,7 +20,7 @@
 
 namespace fggl::phys {
 
-	auto NullPhysics::factory(modules::ModuleService serviceName, modules::Services &serviceManager) -> bool {
+	auto NullPhysics::factory(modules::ServiceName serviceName, modules::Services &serviceManager) -> bool {
 		if (serviceName == phys::PhysicsProvider::service) {
 			serviceManager.bind<phys::PhysicsProvider, NullPhysicsProvider>();
 			return true;
diff --git a/include/fggl/assets/loader.hpp b/include/fggl/assets/loader.hpp
index d7c053a..beedcc2 100644
--- a/include/fggl/assets/loader.hpp
+++ b/include/fggl/assets/loader.hpp
@@ -46,7 +46,7 @@ namespace fggl::assets {
 
 	class Loader {
 		public:
-			constexpr const static modules::ModuleService service = modules::make_service("fggl::assets::Loader");
+			constexpr const static auto service = modules::make_service("fggl::assets::Loader");
 
 			explicit inline Loader(data::Storage *storage, CheckinAdapted *checkin) : m_storage(storage), m_checkin(checkin) {}
 
diff --git a/include/fggl/assets/manager.hpp b/include/fggl/assets/manager.hpp
index ef1ffee..86dd5c1 100644
--- a/include/fggl/assets/manager.hpp
+++ b/include/fggl/assets/manager.hpp
@@ -66,7 +66,7 @@ namespace fggl::assets {
 
 	class AssetManager {
 		public:
-			constexpr const static modules::ModuleService service = modules::make_service("fggl::assets::Manager");
+			constexpr const static modules::ServiceName service = modules::make_service("fggl::assets::Manager");
 
 			AssetManager() = default;
 			virtual ~AssetManager() = default;
diff --git a/include/fggl/assets/module.hpp b/include/fggl/assets/module.hpp
index 388268e..81e09ab 100644
--- a/include/fggl/assets/module.hpp
+++ b/include/fggl/assets/module.hpp
@@ -31,15 +31,15 @@ namespace fggl::assets {
 
 	struct AssetFolders {
 		constexpr static const char *name = "fggl::assets::Folders";
-		constexpr static const std::array<modules::ModuleService, 2> provides = {
+		constexpr static const std::array<modules::ServiceName, 2> provides = {
 			Loader::service,
 			AssetManager::service
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			data::Storage::service,
 			CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
 } // namespace fggl::assets
diff --git a/include/fggl/assets/packed/adapter.hpp b/include/fggl/assets/packed/adapter.hpp
index 1c86492..d229985 100644
--- a/include/fggl/assets/packed/adapter.hpp
+++ b/include/fggl/assets/packed/adapter.hpp
@@ -64,7 +64,7 @@ namespace fggl::assets {
 	 */
 	class CheckinAdapted {
 		public:
-			constexpr const static modules::ModuleService service = modules::make_service("fggl::assets::checkin::debug");
+			constexpr const static auto service = modules::make_service("fggl::assets::checkin::debug");
 
 			using FilePredicate = std::function<AssetTypeID(const std::filesystem::path&)>;
 			using FileLoader = std::function<bool(const std::filesystem::path&, MemoryBlock& block)>;
diff --git a/include/fggl/assets/packed/direct.hpp b/include/fggl/assets/packed/direct.hpp
index f10796d..e184ab4 100644
--- a/include/fggl/assets/packed/direct.hpp
+++ b/include/fggl/assets/packed/direct.hpp
@@ -37,7 +37,7 @@ namespace fggl::assets {
 
 	class RawCheckin {
 		public:
-			constexpr const static modules::ModuleService service = modules::make_service("fggl::assets::checkin");
+			constexpr const static auto service = modules::make_service("fggl::assets::checkin");
 			using DecodeAndCheckFunc = std::function<void(AssetGUID, MemoryBlock& block)>;
 
 			void check(AssetID, AssetTypeID, MemoryBlock& block) const;
diff --git a/include/fggl/assets/packed/module.hpp b/include/fggl/assets/packed/module.hpp
index 8ecc4b2..c99b99d 100644
--- a/include/fggl/assets/packed/module.hpp
+++ b/include/fggl/assets/packed/module.hpp
@@ -30,14 +30,14 @@ namespace fggl::assets {
 
 	struct PackedAssets {
 		constexpr static const char *name = "fggl::assets::packed";
-		constexpr static const std::array<modules::ModuleService, 2> provides = {
+		constexpr static const std::array<modules::ServiceName, 2> provides = {
 			RawCheckin::service,
 			CheckinAdapted::service
 		};
-		constexpr static const std::array<modules::ModuleService, 1> depends = {
+		constexpr static const std::array<modules::ServiceName, 1> depends = {
 			data::Storage::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
 } // namespace fggl::assets
diff --git a/include/fggl/audio/audio.hpp b/include/fggl/audio/audio.hpp
index a31eb6d..3c021a4 100644
--- a/include/fggl/audio/audio.hpp
+++ b/include/fggl/audio/audio.hpp
@@ -57,7 +57,7 @@ namespace fggl::audio {
 	 constexpr auto ASSET_CLIP_SHORT = assets::make_asset_type("Audio:Clip:Short");
 	 constexpr auto ASSET_CLIP_BYTE = assets::make_asset_type("Audio:Clip:Byte");
 
-	constexpr modules::ModuleService SERVICE_AUDIO_PLAYBACK = modules::make_service("fggl::audio::AudioService");
+	constexpr auto SERVICE_AUDIO_PLAYBACK = modules::make_service("fggl::audio::AudioService");
 
 	/**
 	 *
@@ -65,7 +65,7 @@ namespace fggl::audio {
 	 */
 	class AudioService {
 		public:
-			constexpr static const modules::ModuleService service = SERVICE_AUDIO_PLAYBACK;
+			constexpr static const modules::ServiceName service = SERVICE_AUDIO_PLAYBACK;
 
 			virtual void play(const assets::AssetGUID &asset, bool looping = false) = 0;
 			virtual void play(const AudioClipShort &clip, bool looping = false) = 0;
diff --git a/include/fggl/audio/null_audio.hpp b/include/fggl/audio/null_audio.hpp
index 10df67a..fbcd9b3 100644
--- a/include/fggl/audio/null_audio.hpp
+++ b/include/fggl/audio/null_audio.hpp
@@ -39,11 +39,11 @@ namespace fggl::audio {
 
 	struct NullAudio {
 		constexpr static const char *name = "fggl::audio::NULL";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			SERVICE_AUDIO_PLAYBACK
 		};
-		constexpr static const std::array<modules::ModuleService, 0> depends = {};
-		bool factory(modules::ModuleService, modules::Services&);
+		constexpr static const std::array<modules::ServiceName, 0> depends = {};
+		bool factory(modules::ServiceName, modules::Services&);
 	};
 
 
diff --git a/include/fggl/audio/openal/module.hpp b/include/fggl/audio/openal/module.hpp
index 4ca559d..28e6d1f 100644
--- a/include/fggl/audio/openal/module.hpp
+++ b/include/fggl/audio/openal/module.hpp
@@ -35,14 +35,14 @@ namespace fggl::audio {
 
 	struct OpenAL {
 		constexpr static const char *name = "fggl::audio::OpenAL";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			SERVICE_AUDIO_PLAYBACK
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			assets::AssetManager::service,
 			assets::CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
 
diff --git a/include/fggl/data/assimp/module.hpp b/include/fggl/data/assimp/module.hpp
index a10e114..98e7a50 100644
--- a/include/fggl/data/assimp/module.hpp
+++ b/include/fggl/data/assimp/module.hpp
@@ -51,14 +51,14 @@ namespace fggl::data::models {
 
 	struct AssimpModule {
 		constexpr static const char *name = "fggl::data::Assimp";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			MODEL_PROVIDER
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			assets::Loader::service,
 			assets::CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService service, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName service, modules::Services &serviceManager);
 	};
 
 }
diff --git a/include/fggl/data/module.hpp b/include/fggl/data/module.hpp
index f4c9c43..dc9cd5b 100644
--- a/include/fggl/data/module.hpp
+++ b/include/fggl/data/module.hpp
@@ -27,11 +27,11 @@ namespace fggl::data {
 
 	struct LocalStorage {
 		constexpr static const char *name = "fggl::data::Storage";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			SERVICE_STORAGE
 		};
-		constexpr static const std::array<modules::ModuleService, 0> depends = {};
-		static bool factory(modules::ModuleService service, modules::Services &serviceManager);
+		constexpr static const std::array<modules::ServiceName, 0> depends = {};
+		static bool factory(modules::ServiceName service, modules::Services &serviceManager);
 	};
 
 } // namespace fggl::data
diff --git a/include/fggl/data/storage.hpp b/include/fggl/data/storage.hpp
index 0b99259..79fb3a1 100644
--- a/include/fggl/data/storage.hpp
+++ b/include/fggl/data/storage.hpp
@@ -35,11 +35,11 @@ namespace fggl::data {
 
 	enum StorageType { Data, Config, Cache };
 
-	constexpr const modules::ModuleService SERVICE_STORAGE = modules::make_service("fggl::data::Storage");
+	constexpr const auto SERVICE_STORAGE = modules::make_service("fggl::data::Storage");
 
 	class Storage {
 		public:
-			constexpr static modules::ModuleService service = SERVICE_STORAGE;
+			constexpr static auto service = SERVICE_STORAGE;
 
 			Storage(fggl::platform::EnginePaths paths) : m_paths(std::move(paths)) {}
 
diff --git a/include/fggl/display/glfw/module.hpp b/include/fggl/display/glfw/module.hpp
index 8b0940f..b844fa3 100644
--- a/include/fggl/display/glfw/module.hpp
+++ b/include/fggl/display/glfw/module.hpp
@@ -29,18 +29,18 @@ namespace fggl::display {
 
 	struct GLFW {
 		constexpr static const char *name = "fggl::display::glfw";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			WindowService::service
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			fggl::input::Input::service,
 			fggl::gfx::WindowGraphics::service
 		};
 
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
-	bool GLFW::factory(modules::ModuleService service, modules::Services &services) {
+	bool GLFW::factory(modules::ServiceName service, modules::Services &services) {
 		if (service == WindowService::service) {
 			auto input = services.get<input::Input>();
 			auto graphics = services.get<gfx::WindowGraphics>();
diff --git a/include/fggl/display/window.hpp b/include/fggl/display/window.hpp
index 1d0f9f7..59c59aa 100644
--- a/include/fggl/display/window.hpp
+++ b/include/fggl/display/window.hpp
@@ -59,7 +59,7 @@ namespace fggl::display {
 
 	class WindowService {
 		public:
-			constexpr static const modules::ModuleService
+			constexpr static const auto
 				service = modules::make_service("fggl::display::WindowService");
 
 			virtual Window *create() = 0;
diff --git a/include/fggl/entity/loader/loader.hpp b/include/fggl/entity/loader/loader.hpp
index 86e6d4a..5ae0442 100644
--- a/include/fggl/entity/loader/loader.hpp
+++ b/include/fggl/entity/loader/loader.hpp
@@ -44,7 +44,7 @@ namespace fggl::entity {
 
 	class EntityFactory {
 		public:
-			constexpr static const modules::ModuleService service = modules::make_service("fggl::entity:Factory");
+			constexpr static const modules::ServiceName service = modules::make_service("fggl::entity:Factory");
 
 			inline EntityFactory(modules::Services &services) : m_services(services) {}
 
diff --git a/include/fggl/entity/module.hpp b/include/fggl/entity/module.hpp
index cb27abc..e3cd5d5 100644
--- a/include/fggl/entity/module.hpp
+++ b/include/fggl/entity/module.hpp
@@ -31,14 +31,14 @@ namespace fggl::entity {
 
 	struct ECS {
 		constexpr static const char *name = "fggl::entity::ECS";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			EntityFactory::service
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			assets::Loader::service,
 			assets::CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
 	void install_component_factories(EntityFactory *factory);
diff --git a/include/fggl/gfx/interfaces.hpp b/include/fggl/gfx/interfaces.hpp
index 4e1953d..bde4367 100644
--- a/include/fggl/gfx/interfaces.hpp
+++ b/include/fggl/gfx/interfaces.hpp
@@ -34,7 +34,7 @@ namespace fggl::gfx {
 
 	class Graphics {
 		public:
-			constexpr static const modules::ModuleService service = modules::make_service("fggl::gfx::Graphics");
+			constexpr static const auto service = modules::make_service("fggl::gfx::Graphics");
 
 			virtual ~Graphics() = default;
 			virtual void clear() = 0;
diff --git a/include/fggl/gfx/ogl4/module.hpp b/include/fggl/gfx/ogl4/module.hpp
index abde2d3..8cdb6ad 100644
--- a/include/fggl/gfx/ogl4/module.hpp
+++ b/include/fggl/gfx/ogl4/module.hpp
@@ -38,10 +38,10 @@ namespace fggl::gfx {
 
 	struct OpenGL4 {
 		constexpr static const char *name = "fggl::gfx::OpenGL4";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			WindowGraphics::service
 		};
-		constexpr static const std::array<modules::ModuleService, 5> depends = {
+		constexpr static const std::array<modules::ServiceName, 5> depends = {
 			data::Storage::service,
 			assets::AssetManager::service,
 			assets::CheckinAdapted::service,
@@ -49,7 +49,7 @@ namespace fggl::gfx {
 			entity::EntityFactory::service
 		};
 
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
 } //namespace fggl::gfx
diff --git a/include/fggl/gfx/setup.hpp b/include/fggl/gfx/setup.hpp
index 9f1a65c..804bc00 100644
--- a/include/fggl/gfx/setup.hpp
+++ b/include/fggl/gfx/setup.hpp
@@ -37,7 +37,7 @@ namespace fggl::gfx {
 
 	class WindowGraphics {
 		public:
-			constexpr const static modules::ModuleService service = modules::make_service("fggl::gfx::WindowGraphics");
+			constexpr const static auto service = modules::make_service("fggl::gfx::WindowGraphics");
 
 			WindowGraphics() = default;
 			virtual ~WindowGraphics() = default;
diff --git a/include/fggl/gui/fonts.hpp b/include/fggl/gui/fonts.hpp
index 902f85e..4983a0a 100644
--- a/include/fggl/gui/fonts.hpp
+++ b/include/fggl/gui/fonts.hpp
@@ -71,7 +71,7 @@ namespace fggl::gui {
 
 	class FontLibrary {
 		public:
-			constexpr static const modules::ModuleService service = modules::make_service("fggl::gui::font");
+			constexpr static const auto service = modules::make_service("fggl::gui::font");
 
 			explicit FontLibrary(data::Storage *storage);
 			~FontLibrary();
diff --git a/include/fggl/gui/module.hpp b/include/fggl/gui/module.hpp
index cfe1034..14723b4 100644
--- a/include/fggl/gui/module.hpp
+++ b/include/fggl/gui/module.hpp
@@ -39,18 +39,18 @@ namespace fggl::gui {
 
 	struct FreeType {
 		constexpr static const char *name = "fggl::gui::FreeType";
-		constexpr static const std::array<modules::ModuleService, 2> provides = {
+		constexpr static const std::array<modules::ServiceName, 2> provides = {
 			FontLibrary::service,
 			model::WidgetFactory::service
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			data::Storage::service,
 			assets::CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services &serviceManager);
 	};
 
-	bool FreeType::factory(modules::ModuleService service, modules::Services &services) {
+	bool FreeType::factory(modules::ServiceName service, modules::Services &services) {
 		if (service == FontLibrary::service) {
 			auto storage = services.get<data::Storage>();
 			services.create<FontLibrary>(storage);
diff --git a/include/fggl/input/input.hpp b/include/fggl/input/input.hpp
index 4464994..dbdd0a2 100644
--- a/include/fggl/input/input.hpp
+++ b/include/fggl/input/input.hpp
@@ -24,11 +24,11 @@
 
 namespace fggl::input {
 
-	constexpr const modules::ModuleService SERVICE_INPUT = modules::make_service("fggl::input::Input");
+	constexpr const auto SERVICE_INPUT = modules::make_service("fggl::input::Input");
 
 	class Input {
 		public:
-			constexpr static const modules::ModuleService service = SERVICE_INPUT;
+			constexpr static const auto service = SERVICE_INPUT;
 
 			Input() = default;
 			void frame(float dt);
diff --git a/include/fggl/input/module.hpp b/include/fggl/input/module.hpp
index 224e402..b550ab0 100644
--- a/include/fggl/input/module.hpp
+++ b/include/fggl/input/module.hpp
@@ -27,14 +27,14 @@ namespace fggl::input {
 
 	struct Generic {
 		constexpr static const char *name = "fggl::input::Generic";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			SERVICE_INPUT
 		};
-		constexpr static const std::array<modules::ModuleService, 0> depends = {};
-		static bool factory(modules::ModuleService service, modules::Services &services);
+		constexpr static const std::array<modules::ServiceName, 0> depends = {};
+		static bool factory(modules::ServiceName service, modules::Services &services);
 	};
 
-	bool Generic::factory(modules::ModuleService service, modules::Services &services) {
+	bool Generic::factory(modules::ServiceName service, modules::Services &services) {
 		if (service == SERVICE_INPUT) {
 			services.create<input::Input>();
 			return true;
diff --git a/include/fggl/modules/manager.hpp b/include/fggl/modules/manager.hpp
index 6279702..522553a 100644
--- a/include/fggl/modules/manager.hpp
+++ b/include/fggl/modules/manager.hpp
@@ -144,6 +144,23 @@ namespace fggl::modules {
 		public:
 			Manager() = default;
 
+			template<ServiceType T>
+			class Service {
+				public:
+					inline Service(Manager* manager) : m_manager(manager) {}
+
+					inline T* operator->() {
+						if ( m_ptr == nullptr ) {
+							m_ptr = m_manager->get<T>();
+						}
+						return m_ptr;
+					}
+
+				private:
+					Manager* m_manager;
+					std::shared_ptr<T> m_ptr;
+			};
+
 			inline void addVirtual(const Config &config) {
 				assert(!m_locked);
 
@@ -153,7 +170,7 @@ namespace fggl::modules {
 				}
 			}
 
-			template<typename T>
+			template<ModuleType T>
 			void use() {
 				assert(!m_locked);
 
@@ -196,12 +213,18 @@ namespace fggl::modules {
 				return true;
 			}
 
-			template<typename T>
+			template<ServiceType T>
 			T *get() const {
 				assert(m_locked);
 				return m_services.template get<T>();
 			}
 
+			template<ServiceType T>
+			Service<T> getLazy() const {
+				assert(m_locked);
+				return { this };
+			}
+
 			void resolve() {
 				assert( !m_locked );
 				if (!buildGraph()) {
@@ -245,7 +268,7 @@ namespace fggl::modules {
 			Services m_services;
 			std::map<ModuleIdentifier, Config> m_modules;
 			DependencyGraph<ModuleIdentifier> m_dependencies;
-			std::map<ModuleService, ModuleIdentifier> m_serviceProviders;
+			std::map<ServiceName, ModuleIdentifier> m_serviceProviders;
 
 	};
 
diff --git a/include/fggl/modules/module.hpp b/include/fggl/modules/module.hpp
index e3ba6c2..4d0944e 100644
--- a/include/fggl/modules/module.hpp
+++ b/include/fggl/modules/module.hpp
@@ -26,53 +26,39 @@
 #include <memory>
 
 #include "fggl/util/safety.hpp"
+#include "service.hpp"
 
 namespace fggl::modules {
 
+	template<typename T>
+	concept ModuleType = requires(T type) {
+		{ T::provides };
+		{ T::depends };
+	};
+
 	using ModuleIdentifier = std::string;
-	using ModuleService = util::OpaqueName<std::string_view, struct ModuleServiceTag>;
 
-	constexpr ModuleService make_service(const std::string_view name) {
-		return ModuleService::make(name);
-	}
+	using ServiceFactory = std::function<bool(ServiceName , Services &)>;
+	struct Config {
+		ModuleIdentifier name;
+		std::vector<ServiceName> provides;
+		std::vector<ServiceName> depends;
+		ServiceFactory factory = nullptr;
+	};
 
-	class Services {
+	class Module {
 		public:
-			template<typename Svc, typename Impl, typename ...Args>
-			void bind(Args... args) {
-				static_assert(std::is_base_of_v<Svc, Impl>, "Service type must be assignable from implementation type");
-				m_services[Svc::service] = std::make_shared<Impl>(args...);
-			}
+			virtual ~Module() = default;
 
-			template<typename Svc, typename ...Args>
-			Svc *create(Args... args) {
-				auto svc = std::make_shared<Svc>(args...);
-				m_services[Svc::service] = svc;
-				return svc.get();
-			}
+			// copying modules is bad
+			Module(const Module&) = delete;
+			Module& operator=(const Module&) = delete;
 
-			template<typename Svc>
-			void provide(std::shared_ptr<Svc> service) {
-				m_services[Svc::service] = service;
-			}
+			// moving modules is bad
+			Module(Module&&) = delete;
+			Module& operator=(Module&&) = delete;
 
-			template<typename S>
-			S *get() const {
-				auto serviceWrapper = m_services.at(S::service);
-				auto ptr = std::static_pointer_cast<S>(serviceWrapper);
-				return ptr.get();
-			}
-
-		private:
-			std::map<ModuleService, std::shared_ptr<void>> m_services;
-	};
-
-	using ServiceFactory = std::function<bool(ModuleService, Services &)>;
-	struct Config {
-		ModuleIdentifier name;
-		std::vector<ModuleService> provides;
-		std::vector<ModuleService> depends;
-		ServiceFactory factory = nullptr;
+			virtual auto create(ServiceName, Services&) -> bool = 0;
 	};
 
 } // namespace fggl::modules
diff --git a/include/fggl/modules/service.hpp b/include/fggl/modules/service.hpp
new file mode 100644
index 0000000..a1b679b
--- /dev/null
+++ b/include/fggl/modules/service.hpp
@@ -0,0 +1,75 @@
+/*
+ * This file is part of FGGL.
+ *
+ * FGGL is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any
+ * later version.
+ *
+ * FGGL is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License along with FGGL.
+ * If not, see <https://www.gnu.org/licenses/>.
+ */
+
+//
+// Created by webpigeon on 25/03/23.
+//
+
+#ifndef FGGL_MODULES_SERVICE_HPP
+#define FGGL_MODULES_SERVICE_HPP
+
+#include <map>
+#include <memory>
+
+#include "fggl/util/safety.hpp"
+
+namespace fggl::modules {
+
+	using ServiceName = util::OpaqueName<std::string_view, struct ModuleServiceTag>;
+	constexpr ServiceName make_service(const std::string_view name) {
+		return ServiceName::make(name);
+	}
+
+	template<typename T>
+	concept ServiceType = requires(T* type) {
+		{ T::service };
+	};
+
+	template<typename T, typename U>
+	concept Derived = std::is_base_of<U, T>::value;
+
+	class Services {
+		public:
+			template<ServiceType Svc, Derived<Svc> Impl, typename ...Args>
+			void bind(Args... args) {
+				static_assert(std::is_base_of_v<Svc, Impl>, "Service type must be assignable from implementation type");
+				m_services[Svc::service] = std::make_shared<Impl>(args...);
+			}
+
+			template<ServiceType Svc, typename ...Args>
+			Svc *create(Args... args) {
+				auto svc = std::make_shared<Svc>(args...);
+				m_services[Svc::service] = svc;
+				return svc.get();
+			}
+
+			template<ServiceType Svc>
+			void provide(std::shared_ptr<Svc> service) {
+				m_services[Svc::service] = service;
+			}
+
+			template<ServiceType S>
+			S *get() const {
+				auto serviceWrapper = m_services.at(S::service);
+				auto ptr = std::static_pointer_cast<S>(serviceWrapper);
+				return ptr.get();
+			}
+
+		private:
+			std::map<ServiceName, std::shared_ptr<void>> m_services;
+	};
+
+} // namespace fggl::modules
+
+#endif //FGGL_MODULES_SERVICE_HPP
diff --git a/include/fggl/phys/null.hpp b/include/fggl/phys/null.hpp
index 276e22f..d39324d 100644
--- a/include/fggl/phys/null.hpp
+++ b/include/fggl/phys/null.hpp
@@ -70,13 +70,13 @@ namespace fggl::phys {
 
 	struct NullPhysics {
 		constexpr static const char *name = "fggl::phys::null";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			phys::PhysicsProvider::service
 		};
-		constexpr static const std::array<modules::ModuleService, 1> depends = {
+		constexpr static const std::array<modules::ServiceName, 1> depends = {
 			entity::EntityFactory::service
 		};
-		static bool factory(modules::ModuleService serviceName, modules::Services &serviceManager);
+		static bool factory(modules::ServiceName serviceName, modules::Services &serviceManager);
 	};
 
 } // namespace fggl::phys
diff --git a/include/fggl/phys/service.hpp b/include/fggl/phys/service.hpp
index 496529f..c637ca2 100644
--- a/include/fggl/phys/service.hpp
+++ b/include/fggl/phys/service.hpp
@@ -27,7 +27,7 @@ namespace fggl::phys {
 
 	class PhysicsProvider {
 		public:
-			constexpr static const modules::ModuleService service = modules::make_service("fggl::phys::service");
+			constexpr static const auto service = modules::make_service("fggl::phys::service");
 			virtual ~PhysicsProvider() = default;
 			virtual PhysicsEngine *create(entity::EntityManager *entityManager, entity::EntityFactory *factory) = 0;
 	};
diff --git a/include/fggl/script/engine.hpp b/include/fggl/script/engine.hpp
index fb566cf..07ae3b3 100644
--- a/include/fggl/script/engine.hpp
+++ b/include/fggl/script/engine.hpp
@@ -46,7 +46,7 @@ namespace fggl::script {
 
 	class ScriptProvider {
 		public:
-			constexpr static const modules::ModuleService service = modules::make_service("fggl::script::service");
+			constexpr static const modules::ServiceName service = modules::make_service("fggl::script::service");
 			virtual ScriptEngine* create() = 0;
 	};
 
diff --git a/integrations/lua/include/fggl/script/lua/module.hpp b/integrations/lua/include/fggl/script/lua/module.hpp
index c3e2c72..6eda012 100644
--- a/integrations/lua/include/fggl/script/lua/module.hpp
+++ b/integrations/lua/include/fggl/script/lua/module.hpp
@@ -35,14 +35,14 @@ namespace fggl::script::lua {
 
 	struct Lua {
 		constexpr static const char* name = "fggl::script::lua";
-		constexpr static const std::array<modules::ModuleService, 1> provides = {
+		constexpr static const std::array<modules::ServiceName, 1> provides = {
 			script::ScriptProvider::service
 		};
-		constexpr static const std::array<modules::ModuleService, 2> depends = {
+		constexpr static const std::array<modules::ServiceName, 2> depends = {
 			data::SERVICE_STORAGE,
 			assets::CheckinAdapted::service
 		};
-		static bool factory(modules::ModuleService name, modules::Services& serviceManager);
+		static bool factory(modules::ServiceName name, modules::Services& serviceManager);
 	};
 
 } // namespace fggl::script::lua
diff --git a/integrations/lua/src/module.cpp b/integrations/lua/src/module.cpp
index 5356a4b..bfe91a2 100644
--- a/integrations/lua/src/module.cpp
+++ b/integrations/lua/src/module.cpp
@@ -28,10 +28,10 @@ namespace fggl::script::lua {
 		return assets::INVALID_ASSET_TYPE;
 	}
 
-	bool Lua::factory(modules::ModuleService service, modules::Services &serviceManager) {
+	bool Lua::factory(modules::ServiceName service, modules::Services &serviceManager) {
 
 		if ( service == ScriptProvider::service ) {
-			auto storageService = serviceManager.get<data::Storage>();
+			auto *storageService = serviceManager.get<data::Storage>();
 			serviceManager.bind<ScriptProvider,LuaScriptProvider>(storageService);
 
 			auto *assetPacker = serviceManager.get<assets::CheckinAdapted>();
-- 
GitLab