blob: 3764b7cdf919199af7759a488926d10a15fdb643 [file] [log] [blame]
Shawn McCarney6a957f62024-01-10 16:15:19 -06001/**
2 * Copyright © 2024 IBM Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include "rail.hpp"
19
20#include <nlohmann/json.hpp>
21
22#include <cstdint>
23#include <filesystem>
24#include <stdexcept>
25#include <string>
26#include <vector>
27
28namespace phosphor::power::sequencer::config_file_parser
29{
30
31/**
32 * Parses the specified JSON configuration file.
33 *
34 * Returns the corresponding C++ Rail objects.
35 *
36 * Throws a ConfigFileParserError if an error occurs.
37 *
38 * @param pathName configuration file path name
39 * @return vector of Rail objects
40 */
41std::vector<std::unique_ptr<Rail>> parse(const std::filesystem::path& pathName);
42
43/*
44 * Internal implementation details for parse()
45 */
46namespace internal
47{
48
49/**
50 * Returns the specified property of the specified JSON element.
51 *
52 * Throws an invalid_argument exception if the property does not exist.
53 *
54 * @param element JSON element
55 * @param property property name
56 */
57#pragma GCC diagnostic push
58#if __GNUC__ == 13
59#pragma GCC diagnostic ignored "-Wdangling-reference"
60#endif
61inline const nlohmann::json& getRequiredProperty(const nlohmann::json& element,
62 const std::string& property)
63{
64 auto it = element.find(property);
65 if (it == element.end())
66 {
67 throw std::invalid_argument{"Required property missing: " + property};
68 }
69 return *it;
70}
71#pragma GCC diagnostic pop
72
73/**
74 * Parses a JSON element containing a boolean.
75 *
76 * Returns the corresponding C++ boolean value.
77 *
78 * Throws an exception if parsing fails.
79 *
80 * @param element JSON element
81 * @return boolean value
82 */
83inline bool parseBoolean(const nlohmann::json& element)
84{
85 // Verify element contains a boolean
86 if (!element.is_boolean())
87 {
88 throw std::invalid_argument{"Element is not a boolean"};
89 }
90 return element.get<bool>();
91}
92
93/**
94 * Parses a JSON element containing a GPIO.
95 *
96 * Returns the corresponding C++ GPIO object.
97 *
98 * Throws an exception if parsing fails.
99 *
100 * @param element JSON element
101 * @return GPIO object
102 */
103GPIO parseGPIO(const nlohmann::json& element);
104
105/**
106 * Parses a JSON element containing a rail.
107 *
108 * Returns the corresponding C++ Rail object.
109 *
110 * Throws an exception if parsing fails.
111 *
112 * @param element JSON element
113 * @return Rail object
114 */
115std::unique_ptr<Rail> parseRail(const nlohmann::json& element);
116
117/**
118 * Parses a JSON element containing an array of rails.
119 *
120 * Returns the corresponding C++ Rail objects.
121 *
122 * Throws an exception if parsing fails.
123 *
124 * @param element JSON element
125 * @return vector of Rail objects
126 */
127std::vector<std::unique_ptr<Rail>>
128 parseRailArray(const nlohmann::json& element);
129
130/**
131 * Parses the JSON root element of the entire configuration file.
132 *
133 * Returns the corresponding C++ Rail objects.
134 *
135 * Throws an exception if parsing fails.
136 *
137 * @param element JSON element
138 * @return vector of Rail objects
139 */
140std::vector<std::unique_ptr<Rail>> parseRoot(const nlohmann::json& element);
141
142/**
143 * Parses a JSON element containing a string.
144 *
145 * Returns the corresponding C++ string.
146 *
147 * Throws an exception if parsing fails.
148 *
149 * @param element JSON element
150 * @param isEmptyValid indicates whether an empty string value is valid
151 * @return string value
152 */
153inline std::string parseString(const nlohmann::json& element,
154 bool isEmptyValid = false)
155{
156 if (!element.is_string())
157 {
158 throw std::invalid_argument{"Element is not a string"};
159 }
160 std::string value = element.get<std::string>();
161 if (value.empty() && !isEmptyValid)
162 {
163 throw std::invalid_argument{"Element contains an empty string"};
164 }
165 return value;
166}
167
168/**
169 * Parses a JSON element containing an 8-bit unsigned integer.
170 *
171 * Returns the corresponding C++ uint8_t value.
172 *
173 * Throws an exception if parsing fails.
174 *
175 * @param element JSON element
176 * @return uint8_t value
177 */
178inline uint8_t parseUint8(const nlohmann::json& element)
179{
180 // Verify element contains an integer
181 if (!element.is_number_integer())
182 {
183 throw std::invalid_argument{"Element is not an integer"};
184 }
185 int value = element.get<int>();
186 if ((value < 0) || (value > UINT8_MAX))
187 {
188 throw std::invalid_argument{"Element is not an 8-bit unsigned integer"};
189 }
190 return static_cast<uint8_t>(value);
191}
192
193/**
194 * Parses a JSON element containing an unsigned integer.
195 *
196 * Returns the corresponding C++ unsigned int value.
197 *
198 * Throws an exception if parsing fails.
199 *
200 * @param element JSON element
201 * @return unsigned int value
202 */
203inline unsigned int parseUnsignedInteger(const nlohmann::json& element)
204{
205 // Verify element contains an unsigned integer
206 if (!element.is_number_unsigned())
207 {
208 throw std::invalid_argument{"Element is not an unsigned integer"};
209 }
210 return element.get<unsigned int>();
211}
212
213/**
214 * Verifies that the specified JSON element is a JSON array.
215 *
216 * Throws an invalid_argument exception if the element is not an array.
217 *
218 * @param element JSON element
219 */
220inline void verifyIsArray(const nlohmann::json& element)
221{
222 if (!element.is_array())
223 {
224 throw std::invalid_argument{"Element is not an array"};
225 }
226}
227
228/**
229 * Verifies that the specified JSON element is a JSON object.
230 *
231 * Throws an invalid_argument exception if the element is not an object.
232 *
233 * @param element JSON element
234 */
235inline void verifyIsObject(const nlohmann::json& element)
236{
237 if (!element.is_object())
238 {
239 throw std::invalid_argument{"Element is not an object"};
240 }
241}
242
243/**
244 * Verifies that the specified JSON element contains the expected number of
245 * properties.
246 *
247 * Throws an invalid_argument exception if the element contains a different
248 * number of properties. This indicates the element contains an invalid
249 * property.
250 *
251 * @param element JSON element
252 * @param expectedCount expected number of properties in element
253 */
254inline void verifyPropertyCount(const nlohmann::json& element,
255 unsigned int expectedCount)
256{
257 if (element.size() != expectedCount)
258 {
259 throw std::invalid_argument{"Element contains an invalid property"};
260 }
261}
262
263} // namespace internal
264
265} // namespace phosphor::power::sequencer::config_file_parser