5#ifndef ASTARTE_FORMATTER_H
6#define ASTARTE_FORMATTER_H
13#if (__cplusplus >= 202002L) && (__has_include(<format>))
15#define ASTARTE_NS_FORMAT std
17#include <spdlog/fmt/fmt.h>
21#define ASTARTE_NS_FORMAT fmt
27#include "astarte_device_sdk/property.hpp"
43template <
typename OutputIt>
45 static constexpr std::string_view base64_chars =
46 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
47 "abcdefghijklmnopqrstuvwxyz"
51 const size_t len = data.size();
53 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
55 while (idx + 2 < len) {
56 const uint32_t chunk = (data[idx] << 16) | (data[idx + 1] << 8) | data[idx + 2];
57 out = ASTARTE_NS_FORMAT::format_to(
58 out,
"{}{}{}{}", base64_chars[(chunk >> 18) & 0x3F], base64_chars[(chunk >> 12) & 0x3F],
59 base64_chars[(chunk >> 6) & 0x3F], base64_chars[chunk & 0x3F]);
64 uint32_t chunk = data[idx] << 16;
66 chunk |= data[idx + 1] << 8;
69 out = ASTARTE_NS_FORMAT::format_to(out,
"{}{}", base64_chars[(chunk >> 18) & 0x3F],
70 base64_chars[(chunk >> 12) & 0x3F]);
72 out = ASTARTE_NS_FORMAT::format_to(out,
"{}=", base64_chars[(chunk >> 6) & 0x3F]);
74 out = ASTARTE_NS_FORMAT::format_to(out,
"==");
78 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
88template <
typename OutputIt>
89void format_timestamp(OutputIt& out,
const std::chrono::system_clock::time_point& data) {
90 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
91#if (__cplusplus >= 202002L) && (__has_include(<format>))
92 out = ASTARTE_NS_FORMAT::format_to(
94 ASTARTE_NS_FORMAT::format(
"{0:%F}T{0:%T}Z",
95 std::chrono::time_point_cast<std::chrono::milliseconds>(data)));
97 const std::time_t time = std::chrono::system_clock::to_time_t(data);
98 const std::tm utc_tm = *std::gmtime(&time);
99 std::stringstream stream;
100 stream << std::put_time(&utc_tm,
"%FT%T.000Z");
101 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", stream.str());
103 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
113template <
typename OutputIt,
typename T>
115 if constexpr (std::is_same_v<T, bool>) {
116 ASTARTE_NS_FORMAT::format_to(out,
"{}", (data ?
"true" :
"false"));
117 }
else if constexpr (std::is_same_v<T, std::string>) {
118 ASTARTE_NS_FORMAT::format_to(out, R
"("{}")", data);
119 } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
121 }
else if constexpr (std::is_same_v<T, std::chrono::system_clock::time_point>) {
124 ASTARTE_NS_FORMAT::format_to(out,
"{}", data);
135template <
typename OutputIt,
typename T>
137 out = ASTARTE_NS_FORMAT::format_to(out,
"[");
138 for (
size_t i = 0; i < data.size(); ++i) {
140 if (i != data.size() - 1) {
141 out = ASTARTE_NS_FORMAT::format_to(out,
", ");
144 out = ASTARTE_NS_FORMAT::format_to(out,
"]");
163 template <
typename ParseContext>
164 constexpr auto parse(ParseContext& ctx)
const {
174 template <
typename FormatContext>
175 auto format(
const AstarteDeviceSdk::AstarteData& data, FormatContext& ctx)
const {
176 auto out = ctx.out();
178 if (std::holds_alternative<int32_t>(data.
get_raw_data())) {
179 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<int32_t>(data.
get_raw_data()));
180 }
else if (std::holds_alternative<int64_t>(data.
get_raw_data())) {
181 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<int64_t>(data.
get_raw_data()));
182 }
else if (std::holds_alternative<double>(data.
get_raw_data())) {
183 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<double>(data.
get_raw_data()));
184 }
else if (std::holds_alternative<bool>(data.
get_raw_data())) {
185 auto s = (std::get<bool>(data.
get_raw_data()) ?
"true" :
"false");
186 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", s);
187 }
else if (std::holds_alternative<std::string>(data.
get_raw_data())) {
189 ASTARTE_NS_FORMAT::format_to(out, R
"("{}")", std::get<std::string>(data.get_raw_data()));
190 } else if (std::holds_alternative<std::vector<uint8_t>>(data.
get_raw_data())) {
192 }
else if (std::holds_alternative<std::chrono::system_clock::time_point>(data.
get_raw_data())) {
194 std::get<std::chrono::system_clock::time_point>(data.
get_raw_data()));
195 }
else if (std::holds_alternative<std::vector<int32_t>>(data.
get_raw_data())) {
197 }
else if (std::holds_alternative<std::vector<int64_t>>(data.
get_raw_data())) {
199 }
else if (std::holds_alternative<std::vector<double>>(data.
get_raw_data())) {
201 }
else if (std::holds_alternative<std::vector<bool>>(data.
get_raw_data())) {
203 }
else if (std::holds_alternative<std::vector<std::string>>(data.
get_raw_data())) {
205 }
else if (std::holds_alternative<std::vector<std::vector<uint8_t>>>(data.
get_raw_data())) {
207 }
else if (std::holds_alternative<std::vector<std::chrono::system_clock::time_point>>(
210 out, std::get<std::vector<std::chrono::system_clock::time_point>>(data.
get_raw_data()));
227 template <
typename ParseContext>
228 constexpr auto parse(ParseContext& ctx)
const {
238 template <
typename FormatContext>
240 std::string_view name =
"Unknown Type";
259 name =
"LongInteger";
265 name =
"BinaryBlobArray";
268 name =
"BooleanArray";
271 name =
"DatetimeArray";
274 name =
"DoubleArray";
277 name =
"IntegerArray";
280 name =
"LongIntegerArray";
283 name =
"StringArray";
287 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", name);
296struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstarteDatastreamIndividual> {
302 template <
typename ParseContext>
303 constexpr auto parse(ParseContext& ctx)
const {
313 template <
typename FormatContext>
314 auto format(
const AstarteDeviceSdk::AstarteDatastreamIndividual& data, FormatContext& ctx)
const {
315 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", data.
get_value());
319inline std::ostream& operator<<(std::ostream& out,
321 out << ASTARTE_NS_FORMAT::format(
"{}", data);
329struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstarteDatastreamObject> {
335 template <
typename ParseContext>
336 constexpr auto parse(ParseContext& ctx)
const {
346 template <
typename FormatContext>
347 auto format(
const AstarteDeviceSdk::AstarteDatastreamObject& data, FormatContext& ctx)
const {
348 auto out = ctx.out();
349 out = ASTARTE_NS_FORMAT::format_to(out,
"{{");
354 out = ASTARTE_NS_FORMAT::format_to(out,
", ");
356 out = ASTARTE_NS_FORMAT::format_to(out, R
"("{}": {})", pair.first, pair.second);
360 out = ASTARTE_NS_FORMAT::format_to(out,
"}}");
365inline std::ostream& operator<<(std::ostream& out,
367 out << ASTARTE_NS_FORMAT::format(
"{}", data);
376struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstartePropertyIndividual> {
382 template <
typename ParseContext>
383 constexpr auto parse(ParseContext& ctx)
const {
393 template <
typename FormatContext>
394 auto format(
const AstarteDeviceSdk::AstartePropertyIndividual& data, FormatContext& ctx)
const {
396 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", data.
get_value().value());
403inline std::ostream& operator<<(std::ostream& out,
405 out << ASTARTE_NS_FORMAT::format(
"{}", data);
419 template <
typename ParseContext>
420 constexpr auto parse(ParseContext& ctx)
const {
430 template <
typename FormatContext>
431 auto format(
const AstarteDeviceSdk::AstarteMessage& msg, FormatContext& ctx)
const {
432 auto out = ctx.out();
434 out = ASTARTE_NS_FORMAT::format_to(out,
"{{interface: {}, path: {}", msg.
get_interface(),
438 bool is_unset_prop =
false;
440 std::get_if<AstarteDeviceSdk::AstartePropertyIndividual>(&msg.
get_raw_data());
441 if (prop && !prop->get_value().has_value()) {
442 is_unset_prop =
true;
445 if (!is_unset_prop) {
446 out = ASTARTE_NS_FORMAT::format_to(out,
", value: ");
447 std::visit([&out](
const auto& arg) { out = ASTARTE_NS_FORMAT::format_to(out,
"{}", arg); },
451 return ASTARTE_NS_FORMAT::format_to(out,
"}}");
auto get_raw_data() const -> const std::variant< int32_t, int64_t, double, bool, std::string, std::vector< uint8_t >, std::chrono::system_clock::time_point, std::vector< int32_t >, std::vector< int64_t >, std::vector< double >, std::vector< bool >, std::vector< std::string >, std::vector< std::vector< uint8_t > >, std::vector< std::chrono::system_clock::time_point > > &
Return the raw data contained in this class instance.
Representing the Astarte individual datastream data.
Definition individual.hpp:18
auto get_value() const -> const AstarteData &
Get the value contained within the object.
Astarte object class, representing the Astarte object datastream data.
Definition object.hpp:22
auto get_raw_data() const -> const MapType &
Return the raw data contained in this class instance.
auto get_raw_data() const -> const std::variant< AstarteDatastreamIndividual, AstarteDatastreamObject, AstartePropertyIndividual > &
Return the raw data contained in this class instance.
auto get_path() const -> const std::string &
Get the path of the message.
auto get_interface() const -> const std::string &
Get the interface of the message.
Representing the Astarte individual datastream data.
Definition property.hpp:20
auto get_value() const -> const std::optional< AstarteData > &
Get the value contained within the object.
Astarte individual datastream class and its related methods.
Astarte message class and its related methods.
Umbrella namespace for the Astarte device SDK.
Definition data.hpp:25
AstarteType
Possible Astarte types.
Definition type.hpp:18
@ kLongIntegerArray
Long integer array Astarte type.
Definition type.hpp:44
@ kIntegerArray
Integer array Astarte type.
Definition type.hpp:42
@ kDouble
Double Astarte type.
Definition type.hpp:26
@ kBoolean
Boolean Astarte type.
Definition type.hpp:22
@ kDatetime
Date-time Astarte type.
Definition type.hpp:24
@ kBinaryBlob
Binary blob Astarte type.
Definition type.hpp:20
@ kDoubleArray
Double array Astarte type.
Definition type.hpp:40
@ kStringArray
String array Astarte type.
Definition type.hpp:46
@ kBooleanArray
Boolean array Astarte type.
Definition type.hpp:36
@ kInteger
Integer Astarte type.
Definition type.hpp:28
@ kDatetimeArray
Datetime array Astarte type.
Definition type.hpp:38
@ kString
String Astarte type.
Definition type.hpp:32
@ kBinaryBlobArray
Binary blob array Astarte type.
Definition type.hpp:34
@ kLongInteger
Long integer Astarte type.
Definition type.hpp:30
Contain utility functions for formatting data.
Definition formatter.hpp:33
void format_timestamp(OutputIt &out, const std::chrono::system_clock::time_point &data)
Format a timestamp into an ISO 8601 string literal.
Definition formatter.hpp:89
void format_vector(OutputIt &out, const std::vector< T > &data)
Format a generic vector into a comma-separated list in brackets.
Definition formatter.hpp:136
void format_base64(OutputIt &out, const std::vector< uint8_t > &data)
Format a vector of bytes into a Base64 string literal.
Definition formatter.hpp:44
void format_data(OutputIt &out, const T &data)
Format a generic data type into an output iterator.
Definition formatter.hpp:114
Astarte object class and its related methods.
Types definitions for communication with Astarte.