changeset 276:ec0a2b5493f8

ini: simplify INI code, use templates less less magic voodoo code
author Paper <paper@paper.us.eu.org>
date Mon, 22 Apr 2024 19:10:28 -0400
parents 22f9aacf6ac1
children a796e97cc86d
files Makefile.am include/core/ini.h src/core/config.cc src/core/ini.cc
diffstat 4 files changed, 56 insertions(+), 93 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.am	Thu Apr 18 19:23:31 2024 -0400
+++ b/Makefile.am	Mon Apr 22 19:10:28 2024 -0400
@@ -189,6 +189,7 @@
 	src/core/date.cc		\
 	src/core/filesystem.cc		\
 	src/core/http.cc		\
+	src/core/ini.cc			\
 	src/core/json.cc		\
 	src/core/strings.cc		\
 	src/core/time.cc		\
--- a/include/core/ini.h	Thu Apr 18 19:23:31 2024 -0400
+++ b/include/core/ini.h	Mon Apr 22 19:10:28 2024 -0400
@@ -3,64 +3,17 @@
 
 #define MINI_CASE_SENSITIVE
 #include "core/strings.h"
-#include "gui/translate/anime.h"
-#include "gui/translate/config.h"
 #include "mini/ini.h"
 #include <string>
-#include <type_traits>
 
 namespace INI {
 
-/* very simple tutorial on how to give anyone who reads
-   your code an aneurysm */
-template<typename T, typename = void>
-struct is_toutf8string_available : std::false_type {};
-
-template<typename T>
-struct is_toutf8string_available<T, std::void_t<decltype(Strings::ToUtf8String(std::declval<T>()))>> : std::true_type {
-};
-
-template<typename T, typename = void>
-struct is_translation_available : std::false_type {};
-
-template<typename T>
-struct is_translation_available<T, std::void_t<decltype(Translate::ToString(std::declval<T>()))>> : std::true_type {};
+std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, const std::string& key, const std::string& def);
+bool GetIniBool(const mINI::INIStructure& ini, const std::string& section, const std::string& key, bool def);
 
 template<typename T>
-T GetIniValue(const mINI::INIStructure& ini, const std::string& section, const std::string& value, const T& def) {
-	if (!ini.has(section) || !ini.get(section).has(value))
-		return def;
-
-	const std::string val = ini.get(section).get(value);
-
-	if constexpr (std::is_integral<T>::value) {
-		/* Integer? */
-		if constexpr (std::is_same<T, bool>::value) {
-			/* Boolean? */
-			return Strings::ToBool(val, def);
-		} else {
-			/* Always fall back to long long */
-			return Strings::ToInt<T>(val, def);
-		}
-	} else {
-		return val;
-	}
-}
-
-/* this should be able to handle most of our custom types */
-template<typename T>
-void SetIniValue(mINI::INIStructure& ini, const std::string& section, const std::string& key, const T& value) {
-	auto& ini_key = ini[section][key];
-
-	if constexpr (is_translation_available<T>::value) {
-		/* prioritize translation */
-		ini_key = Translate::ToString(value);
-	} else if constexpr (std::is_same<T, std::string>::value) {
-		/* lmfao */
-		ini_key = value;
-	} else if constexpr (is_toutf8string_available<T>::value) {
-		ini_key = Strings::ToUtf8String(value);
-	}
+T GetIniInteger(const mINI::INIStructure& ini, const std::string& section, const std::string& key, T def) {
+	return Strings::ToInt<T>(GetIniString(ini, section, key, ""), def);
 }
 
 } // namespace INI
--- a/src/core/config.cc	Thu Apr 18 19:23:31 2024 -0400
+++ b/src/core/config.cc	Mon Apr 22 19:10:28 2024 -0400
@@ -39,31 +39,31 @@
 	mINI::INIStructure ini;
 	file.read(ini);
 
-	service = Translate::ToService(INI::GetIniValue<std::string>(ini, "General", "Service", "None"));
+	service = Translate::ToService(INI::GetIniString(ini, "General", "Service", "None"));
 
 	anime_list.score_format =
-	    Translate::ToScoreFormat(INI::GetIniValue<std::string>(ini, "Anime List", "Score format", "POINT_100"));
+	    Translate::ToScoreFormat(INI::GetIniString(ini, "Anime List", "Score format", "POINT_100"));
 	anime_list.language =
-	    Translate::ToLanguage(INI::GetIniValue<std::string>(ini, "Anime List", "Title language", "Romaji"));
-	anime_list.display_aired_episodes = INI::GetIniValue<bool>(ini, "Anime List", "Display only aired episodes", true);
+	    Translate::ToLanguage(INI::GetIniString(ini, "Anime List", "Title language", "Romaji"));
+	anime_list.display_aired_episodes = INI::GetIniBool(ini, "Anime List", "Display only aired episodes", true);
 	anime_list.display_available_episodes =
-	    INI::GetIniValue<bool>(ini, "Anime List", "Display only available episodes in library", true);
+	    INI::GetIniBool(ini, "Anime List", "Display only available episodes in library", true);
 	anime_list.highlight_anime_if_available =
-	    INI::GetIniValue<bool>(ini, "Anime List", "Highlight anime if available", true);
+	    INI::GetIniBool(ini, "Anime List", "Highlight anime if available", true);
 
 	if (anime_list.highlight_anime_if_available) // sanity check
 		anime_list.highlighted_anime_above_others =
-		    INI::GetIniValue<bool>(ini, "Anime List", "Display highlighted anime above others", false);
+		    INI::GetIniBool(ini, "Anime List", "Display highlighted anime above others", false);
 	else
 		anime_list.highlighted_anime_above_others = false;
 
-	auth.anilist.auth_token = INI::GetIniValue<std::string>(ini, "Authentication/AniList", "Auth Token", "");
-	auth.anilist.user_id = INI::GetIniValue<int>(ini, "Authentication/AniList", "User ID", 0);
+	auth.anilist.auth_token = INI::GetIniString(ini, "Authentication/AniList", "Auth Token", "");
+	auth.anilist.user_id = INI::GetIniInteger<int>(ini, "Authentication/AniList", "User ID", 0);
 
-	torrents.feed_link = INI::GetIniValue<std::string>(ini, "Torrents", "RSS feed",
-	                                                   "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
+	torrents.feed_link = INI::GetIniString(ini, "Torrents", "RSS feed",
+	                                       "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
 
-	recognition.detect_media_players = INI::GetIniValue<bool>(ini, "Recognition", "Detect media players", true);
+	recognition.detect_media_players = INI::GetIniBool(ini, "Recognition", "Detect media players", true);
 
 	/* lots of dumb logic to import the player data */
 	{
@@ -89,28 +89,28 @@
 		switch (player.type) {
 			default:
 			case animone::PlayerType::Default:
-				enabled = INI::GetIniValue<bool>(ini, "Recognition/Players", player.name, true);
+				enabled = INI::GetIniBool(ini, "Recognition/Players", player.name, true);
 				break;
 			case animone::PlayerType::WebBrowser:
-				enabled = INI::GetIniValue<bool>(ini, "Recognition/Browsers", player.name, true);
+				enabled = INI::GetIniBool(ini, "Recognition/Browsers", player.name, true);
 				break;
 		}
 	}
 
 	locale.RefreshAvailableLocales();
 	locale.SetActiveLocale(
-	    QLocale(Strings::ToQString(INI::GetIniValue<std::string>(ini, "General", "Locale", "en_US"))));
+	    QLocale(Strings::ToQString(INI::GetIniString(ini, "General", "Locale", "en_US"))));
 
-	theme.SetTheme(Translate::ToTheme(INI::GetIniValue<std::string>(ini, "Appearance", "Theme", "Default")));
+	theme.SetTheme(Translate::ToTheme(INI::GetIniString(ini, "Appearance", "Theme", "Default")));
 
 	{
-		std::vector<std::string> v = Strings::Split(INI::GetIniValue<std::string>(ini, "Library", "Folders", ""), ";");
+		std::vector<std::string> v = Strings::Split(INI::GetIniString(ini, "Library", "Folders", ""), ";");
 		for (const auto& s : v)
 			if (!library.paths.count(s))
 				library.paths.insert(s);
 	}
 
-	library.real_time_monitor = INI::GetIniValue<bool>(ini, "Library", "Real-time monitor", true);
+	library.real_time_monitor = INI::GetIniBool(ini, "Library", "Real-time monitor", true);
 
 	return 0;
 }
@@ -122,39 +122,32 @@
 	mINI::INIFile file(cfg_path.string());
 	mINI::INIStructure ini;
 
-	INI::SetIniValue(ini, "General", "Service", service);
-	INI::SetIniValue(ini, "General", "Locale", locale.GetLocale().name());
+	ini["General"]["Service"] = Translate::ToString(service);
+	ini["General"]["Locale"] = Strings::ToUtf8String(locale.GetLocale().name());
 
-	INI::SetIniValue(ini, "Anime List", "Score format", Translate::ToString(anime_list.score_format));
-	INI::SetIniValue(ini, "Anime List", "Title language", anime_list.language);
-	INI::SetIniValue(ini, "Anime List", "Display only aired episodes", anime_list.display_aired_episodes);
-	INI::SetIniValue(ini, "Anime List", "Display only available episodes in library",
-	                 anime_list.display_available_episodes);
-	INI::SetIniValue(ini, "Anime List", "Highlight anime if available", anime_list.highlight_anime_if_available);
-	INI::SetIniValue(ini, "Anime List", "Display highlighted anime above others",
-	                 anime_list.highlighted_anime_above_others);
+	ini["Anime List"]["Score format"] = Translate::ToString(anime_list.score_format);
+	ini["Anime List"]["Title language"] = Translate::ToString(anime_list.language);
+	ini["Anime List"]["Display only aired episodes"] = Strings::ToUtf8String(anime_list.display_aired_episodes);
+	ini["Anime List"]["Display only available episodes in library"] = Strings::ToUtf8String(anime_list.display_available_episodes);
+	ini["Anime List"]["Highlight anime if available"] = Strings::ToUtf8String(anime_list.highlight_anime_if_available);
+	ini["Anime List"]["Display highlighted anime above others"] = Strings::ToUtf8String(anime_list.highlighted_anime_above_others);
 
-	INI::SetIniValue(ini, "Authentication/AniList", "Auth Token", auth.anilist.auth_token);
-	INI::SetIniValue(ini, "Authentication/AniList", "User ID", auth.anilist.user_id);
+	ini["Authentication/AniList"]["Auth Token"] = auth.anilist.auth_token;
+	ini["Authentication/AniList"]["User ID"] = auth.anilist.user_id;
 
-	INI::SetIniValue(ini, "Appearance", "Theme", theme.GetTheme());
+	ini["Appearance"]["Theme"] = Translate::ToString(theme.GetTheme());
 
-	INI::SetIniValue(ini, "Torrents", "RSS feed", torrents.feed_link);
+	ini["Torrents"]["RSS feed"] = torrents.feed_link;
 
-	INI::SetIniValue(ini, "Recognition", "Detect media players", recognition.detect_media_players);
+	ini["Recognition"]["Detect media players"] = Strings::ToUtf8String(recognition.detect_media_players);
 
 	for (const auto& [enabled, player] : recognition.players) {
-		switch (player.type) {
-			default:
-			case animone::PlayerType::Default: INI::SetIniValue(ini, "Recognition/Players", player.name, enabled); break;
-			case animone::PlayerType::WebBrowser:
-				INI::SetIniValue(ini, "Recognition/Browsers", player.name, enabled);
-				break;
-		}
+		const std::string section = (player.type == animone::PlayerType::WebBrowser) ? "Recognition/Players" : "Recognition/Browsers";
+		ini[section][player.name] = Strings::ToUtf8String(enabled);
 	}
 
-	INI::SetIniValue(ini, "Library", "Folders", Strings::Implode(library.paths, ";"));
-	INI::SetIniValue(ini, "Library", "Real-time monitor", library.real_time_monitor);
+	ini["Library"]["Folders"] = Strings::Implode(library.paths, ";");
+	ini["Library"]["Real-time monitor"] = Strings::ToUtf8String(library.real_time_monitor);
 
 	file.write(ini);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/src/core/ini.cc	Mon Apr 22 19:10:28 2024 -0400
@@ -0,0 +1,16 @@
+#include "core/ini.h"
+
+namespace INI {
+
+std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, const std::string& key, const std::string& def) {
+	if (!ini.has(section) || !ini.get(section).has(key))
+		return def;
+
+	return ini.get(section).get(key);
+}
+
+bool GetIniBool(const mINI::INIStructure& ini, const std::string& section, const std::string& key, bool def) {
+	return Strings::ToBool(GetIniString(ini, section, key, ""), def);
+}
+
+}