StormByte-Config 2.0.0
C++26 configuration-document module of the StormByte suite
 
Loading...
Searching...
No Matches
base.txx
Go to the documentation of this file.
1/*
2 * Copyright (C) 2024-2026 David C. Manuelda (StormBytePP)
3 *
4 * This file is part of StormByte-Config.
5 *
6 * StormByte-Config original source is dual-licensed:
7 *
8 * 1. GNU Lesser General Public License v3.0 (or later)
9 * You may redistribute and/or modify this file under the terms of the
10 * GNU Lesser General Public License as published by the Free Software
11 * Foundation, either version 3 of the License, or (at your option)
12 * any later version.
13 *
14 * 2. Commercial license
15 * Alternatively, this file may be used under the terms of a commercial
16 * license agreement with the copyright holder
17 * (David C. Manuelda <StormByte@gmail.com>).
18 *
19 * Both licenses apply only to original StormByte-Config source in this
20 * repository. They do not cover other StormByte modules or any third-party
21 * material shipped with this repository. The bundled StormByte Base tree
22 * under thirdparty/ remains under its own license.
23 *
24 * Neither license grants any patent rights. Any patent licenses required
25 * to use this software or third-party components must be obtained separately
26 * from the patent holders.
27 *
28 * StormByte-Config is distributed in the hope that it will be useful,
29 * but WITHOUT ANY WARRANTY; without even the implied warranty of
30 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
31 * GNU Lesser General Public License for more details.
32 *
33 * You should have received a copy of the GNU Lesser General Public License
34 * version 3 along with StormByte-Config. If not, see
35 * <https://www.gnu.org/licenses/lgpl-3.0.html>.
36 *
37 * SPDX-License-Identifier: LGPL-3.0-or-later OR LicenseRef-StormByte-Commercial
38 */
39
40#pragma once
41
42#include <StormByte/config/item/comment.hxx>
43#include <StormByte/config/item/group.hxx>
44#include <StormByte/config/item/list.hxx>
45#include <StormByte/config/item/value.hxx>
46#include <StormByte/type_traits.hxx>
47
48#include <string_view>
49
50namespace StormByte::Config::Item {
51 namespace {
52 [[noreturn]] void FailAs(const Base& item, const char* wanted) {
53 throw Exception("Item {} is not {}", static_cast<std::string_view>(item.Name()), wanted);
54 }
55
56 Value& RequireValue(Base& item) {
57 if (item.Type() != Item::Type::Integer && item.Type() != Item::Type::Double &&
58 item.Type() != Item::Type::Bool && item.Type() != Item::Type::String &&
59 item.Type() != Item::Type::Binary)
60 FailAs(item, "Value");
61 return static_cast<Value&>(item);
62 }
63
64 const Value& RequireValue(const Base& item) {
65 if (item.Type() != Item::Type::Integer && item.Type() != Item::Type::Double &&
66 item.Type() != Item::Type::Bool && item.Type() != Item::Type::String &&
67 item.Type() != Item::Type::Binary)
68 FailAs(item, "Value");
69 return static_cast<const Value&>(item);
70 }
71 }
72
73 template<class T>
74 decltype(auto) Base::As() {
75 if constexpr (StormByte::Type::SameAs<T, Value>) {
76 return RequireValue(*this);
77 } else if constexpr (StormByte::Type::SameAs<T, Container>) {
78 if (this->Type() != Item::Type::Container)
79 FailAs(*this, "Container");
80 return static_cast<Container&>(*this);
81 } else if constexpr (StormByte::Type::SameAs<T, Group>) {
82 if (this->Type() != Item::Type::Container)
83 FailAs(*this, "Group");
84 auto& container = static_cast<Container&>(*this);
85 if (container.ContainerType() != Item::ContainerType::Group)
86 FailAs(*this, "Group");
87 return static_cast<Group&>(*this);
88 } else if constexpr (StormByte::Type::SameAs<T, List>) {
89 if (this->Type() != Item::Type::Container)
90 FailAs(*this, "List");
91 auto& container = static_cast<Container&>(*this);
92 if (container.ContainerType() != Item::ContainerType::List)
93 FailAs(*this, "List");
94 return static_cast<List&>(*this);
95 } else if constexpr (StormByte::Type::SameAs<T, Integer>) {
96 return static_cast<int&>(RequireValue(*this));
97 } else if constexpr (StormByte::Type::SameAs<T, Double>) {
98 return static_cast<double>(RequireValue(*this));
99 } else if constexpr (StormByte::Type::SameAs<T, Bool>) {
100 return static_cast<bool&>(RequireValue(*this));
101 } else if constexpr (StormByte::Type::SameAs<T, Text>) {
102 return static_cast<StormByte::Safe::String&>(RequireValue(*this));
103 } else if constexpr (StormByte::Type::SameAs<T, Binary>) {
104 return static_cast<StormByte::BinaryData&>(RequireValue(*this));
105 } else if constexpr (requires { T::CommentTag; }) {
106 if (this->Type() != Item::Type::Comment)
107 FailAs(*this, "Comment");
108 return static_cast<T&>(*this);
109 } else {
110 static_assert(StormByte::Type::SameAs<T, Value>, "Unsupported As<T>");
111 }
112 }
113
114 template<class T>
115 decltype(auto) Base::As() const {
116 if constexpr (StormByte::Type::SameAs<T, Value>) {
117 return RequireValue(*this);
118 } else if constexpr (StormByte::Type::SameAs<T, Container>) {
119 if (this->Type() != Item::Type::Container)
120 FailAs(*this, "Container");
121 return static_cast<const Container&>(*this);
122 } else if constexpr (StormByte::Type::SameAs<T, Group>) {
123 if (this->Type() != Item::Type::Container)
124 FailAs(*this, "Group");
125 const auto& container = static_cast<const Container&>(*this);
126 if (container.ContainerType() != Item::ContainerType::Group)
127 FailAs(*this, "Group");
128 return static_cast<const Group&>(*this);
129 } else if constexpr (StormByte::Type::SameAs<T, List>) {
130 if (this->Type() != Item::Type::Container)
131 FailAs(*this, "List");
132 const auto& container = static_cast<const Container&>(*this);
133 if (container.ContainerType() != Item::ContainerType::List)
134 FailAs(*this, "List");
135 return static_cast<const List&>(*this);
136 } else if constexpr (StormByte::Type::SameAs<T, Integer>) {
137 return static_cast<const int&>(RequireValue(*this));
138 } else if constexpr (StormByte::Type::SameAs<T, Double>) {
139 return static_cast<double>(RequireValue(*this));
140 } else if constexpr (StormByte::Type::SameAs<T, Bool>) {
141 return static_cast<const bool&>(RequireValue(*this));
142 } else if constexpr (StormByte::Type::SameAs<T, Text>) {
143 return static_cast<const StormByte::Safe::String&>(RequireValue(*this));
144 } else if constexpr (StormByte::Type::SameAs<T, Binary>) {
145 return static_cast<const StormByte::BinaryData&>(RequireValue(*this));
146 } else if constexpr (requires { T::CommentTag; }) {
147 if (this->Type() != Item::Type::Comment)
148 FailAs(*this, "Comment");
149 return static_cast<const T&>(*this);
150 } else {
151 static_assert(StormByte::Type::SameAs<T, Value>, "Unsupported As<T>");
152 }
153 }
154}