ifw-daq  1.0.0
IFW Data Acquisition modules
json.cpp
Go to the documentation of this file.
1 /**
2  * @file
3  * @ingroup daq_ocm_libfits
4  * @copyright 2021 ESO - European Southern Observatory
5  *
6  * @brief Definition of contents from fits/json.hpp
7  */
8 #include <boost/assign.hpp>
9 #include <boost/range/adaptor/indexed.hpp>
10 
11 #include <daq/fits/json.hpp>
12 #include <fmt/format.h>
13 #include <nlohmann/json.hpp>
14 
15 #include <iostream>
16 namespace daq::fits {
17 
18 namespace {
19 /**
20  * Parse the JSON object that defines a keyword.
21  * It requires that @a obj is a JSON object with the following fields:
22  * - name:str
23  * - value:bool,str,number
24  * - [comment:str] (optional)
25  *
26  * @pre @a `obj.is_object() == true`
27  */
28 template <class KeywordType>
29 KeywordType ParseKeywordObject(nlohmann::json const& obj) {
30  assert(obj.is_object());
31 
32  if (!obj.contains("name")) {
33  throw std::invalid_argument("field 'name' missing");
34  }
35  if (!obj["name"].is_string()) {
36  throw std::invalid_argument("field 'name' must be a string");
37  }
38  if (!obj.contains("value")) {
39  throw std::invalid_argument("field 'value' missing");
40  }
41 
42  typename KeywordType::ValueType kw_value;
43  auto name = obj["name"].get<std::string>();
44  auto value = obj["value"];
45  if (value.is_boolean()) {
46  kw_value = value.get<bool>();
47  } else if (value.is_string()) {
48  kw_value = value.get<std::string>();
49  } else if (value.is_number_float()) {
50  kw_value = value.get<double>();
51  } else if (value.is_number_unsigned()) {
52  kw_value = value.get<uint64_t>();
53  } else if (value.is_number_integer()) {
54  kw_value = value.get<int64_t>();
55  } else {
56  throw std::invalid_argument(fmt::format("unsupported type: {}", value.type_name()));
57  }
58 
59  std::optional<std::string> kw_comment;
60  if (obj.contains("comment")) {
61  auto const& comment = obj["comment"];
62  if (!comment.is_string()) {
63  throw std::invalid_argument(fmt::format(
64  "field 'comment' type must be a string, got '{}'", comment.type_name()));
65  }
66  kw_comment = comment.get<std::string>();
67  }
68  return KeywordType(name, kw_value, kw_comment);
69 }
70 
71 } // namespace
72 
73 std::vector<KeywordVariant> ParseJsonKeywords(char const* keywords) {
74  // outer value must be an array
75  auto parsed = nlohmann::json::parse(keywords);
76  return ParseJsonKeywords(parsed);
77 }
78 
79 std::vector<KeywordVariant> ParseJsonKeywords(nlohmann::json const& keywords) {
80  using namespace boost::assign;
81  using namespace boost::adaptors;
82 
83  if (!keywords.is_array()) {
84  throw std::invalid_argument(
85  fmt::format("root element parsing error: expected array of objects but got '{}'",
86  keywords.type_name()));
87  }
88 
89  std::vector<KeywordVariant> parsed_keywords;
90  parsed_keywords.reserve(keywords.size());
91 
92  for (auto const& index : keywords | indexed(0u)) {
93  auto const& kw_obj = index.value();
94 
95  if (!kw_obj.is_object()) {
96  throw std::invalid_argument(
97  fmt::format("keyword [{}]: parsing error, expected array but got {}",
98  index.index(),
99  keywords.type_name()));
100  }
101  if (!kw_obj.contains("type")) {
102  throw std::invalid_argument(
103  fmt::format("keyword [{}]: parsing error: Field 'type' "
104  "missing",
105  index.index()));
106  }
107  if (!kw_obj["type"].is_string()) {
108  throw std::invalid_argument(
109  fmt::format("keyword [{}]: parsing error: Field 'type' "
110  "must be string",
111  index.index()));
112  }
113  try {
114  auto type = kw_obj["type"].get<std::string>();
115  if (type == "valueKeyword") {
116  parsed_keywords.push_back(ParseKeywordObject<ValueKeyword>(kw_obj));
117  // @todo validate parsed values (e.g. keyword length et.c.)?
118  } else if (type == "esoKeyword") {
119  parsed_keywords.push_back(ParseKeywordObject<EsoKeyword>(kw_obj));
120  // @todo validate parsed values (e.g. keyword length et.c.)?
121  } else {
122  throw std::invalid_argument(
123  fmt::format("unknown keyword type, expected"
124  "one of 'valueKeyword' or 'esoKeyword', but got "
125  "{}",
126  type));
127  }
128  } catch (std::invalid_argument const& exc) {
129  throw std::invalid_argument(
130  fmt::format("keyword [{}]: parsing error: {}", index.index(), exc.what()));
131  }
132  }
133 
134  return parsed_keywords;
135 }
136 
137 } // namespace daq::fits
daq::fits
Definition: cfitsio.cpp:14
json.hpp
Contains data structure for FITS keywords.
daq::fits::ParseJsonKeywords
std::vector< KeywordVariant > ParseJsonKeywords(char const *keywords)
Parse and return FITS keywords.
Definition: json.cpp:73