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
28#include "astarte_device_sdk/property.hpp"
45template <
typename OutputIt>
47 static constexpr std::string_view base64_chars =
48 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
49 "abcdefghijklmnopqrstuvwxyz"
53 const size_t len = data.size();
55 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
57 while (idx + 2 < len) {
58 const uint32_t chunk = (data[idx] << 16) | (data[idx + 1] << 8) | data[idx + 2];
59 out = ASTARTE_NS_FORMAT::format_to(
60 out,
"{}{}{}{}", base64_chars[(chunk >> 18) & 0x3F], base64_chars[(chunk >> 12) & 0x3F],
61 base64_chars[(chunk >> 6) & 0x3F], base64_chars[chunk & 0x3F]);
66 uint32_t chunk = data[idx] << 16;
68 chunk |= data[idx + 1] << 8;
71 out = ASTARTE_NS_FORMAT::format_to(out,
"{}{}", base64_chars[(chunk >> 18) & 0x3F],
72 base64_chars[(chunk >> 12) & 0x3F]);
74 out = ASTARTE_NS_FORMAT::format_to(out,
"{}=", base64_chars[(chunk >> 6) & 0x3F]);
76 out = ASTARTE_NS_FORMAT::format_to(out,
"==");
80 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
90template <
typename OutputIt>
91void format_timestamp(OutputIt& out,
const std::chrono::system_clock::time_point& data) {
92 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
93#if (__cplusplus >= 202002L) && (__has_include(<format>))
94 out = ASTARTE_NS_FORMAT::format_to(
96 ASTARTE_NS_FORMAT::format(
"{0:%F}T{0:%T}Z",
97 std::chrono::time_point_cast<std::chrono::milliseconds>(data)));
99 const std::time_t time = std::chrono::system_clock::to_time_t(data);
100 const std::tm utc_tm = *std::gmtime(&time);
101 std::stringstream stream;
102 stream << std::put_time(&utc_tm,
"%FT%T.000Z");
103 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", stream.str());
105 out = ASTARTE_NS_FORMAT::format_to(out,
"\"");
115template <
typename OutputIt,
typename T>
117 if constexpr (std::is_same_v<T, bool>) {
118 ASTARTE_NS_FORMAT::format_to(out,
"{}", (data ?
"true" :
"false"));
119 }
else if constexpr (std::is_same_v<T, std::string>) {
120 ASTARTE_NS_FORMAT::format_to(out, R
"("{}")", data);
121 } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
123 }
else if constexpr (std::is_same_v<T, std::chrono::system_clock::time_point>) {
126 ASTARTE_NS_FORMAT::format_to(out,
"{}", data);
137template <
typename OutputIt,
typename T>
139 out = ASTARTE_NS_FORMAT::format_to(out,
"[");
140 for (
size_t i = 0; i < data.size(); ++i) {
142 if (i != data.size() - 1) {
143 out = ASTARTE_NS_FORMAT::format_to(out,
", ");
146 out = ASTARTE_NS_FORMAT::format_to(out,
"]");
165 template <
typename ParseContext>
166 constexpr auto parse(ParseContext& ctx)
const {
176 template <
typename FormatContext>
177 auto format(
const AstarteDeviceSdk::AstarteData& data, FormatContext& ctx)
const {
178 auto out = ctx.out();
180 if (std::holds_alternative<int32_t>(data.
get_raw_data())) {
181 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<int32_t>(data.
get_raw_data()));
182 }
else if (std::holds_alternative<int64_t>(data.
get_raw_data())) {
183 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<int64_t>(data.
get_raw_data()));
184 }
else if (std::holds_alternative<double>(data.
get_raw_data())) {
185 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", std::get<double>(data.
get_raw_data()));
186 }
else if (std::holds_alternative<bool>(data.
get_raw_data())) {
187 auto s = (std::get<bool>(data.
get_raw_data()) ?
"true" :
"false");
188 out = ASTARTE_NS_FORMAT::format_to(out,
"{}", s);
189 }
else if (std::holds_alternative<std::string>(data.
get_raw_data())) {
191 ASTARTE_NS_FORMAT::format_to(out, R
"("{}")", std::get<std::string>(data.get_raw_data()));
192 } else if (std::holds_alternative<std::vector<uint8_t>>(data.
get_raw_data())) {
194 }
else if (std::holds_alternative<std::chrono::system_clock::time_point>(data.
get_raw_data())) {
196 std::get<std::chrono::system_clock::time_point>(data.
get_raw_data()));
197 }
else if (std::holds_alternative<std::vector<int32_t>>(data.
get_raw_data())) {
199 }
else if (std::holds_alternative<std::vector<int64_t>>(data.
get_raw_data())) {
201 }
else if (std::holds_alternative<std::vector<double>>(data.
get_raw_data())) {
203 }
else if (std::holds_alternative<std::vector<bool>>(data.
get_raw_data())) {
205 }
else if (std::holds_alternative<std::vector<std::string>>(data.
get_raw_data())) {
207 }
else if (std::holds_alternative<std::vector<std::vector<uint8_t>>>(data.
get_raw_data())) {
209 }
else if (std::holds_alternative<std::vector<std::chrono::system_clock::time_point>>(
212 out, std::get<std::vector<std::chrono::system_clock::time_point>>(data.
get_raw_data()));
220 out << ASTARTE_NS_FORMAT::format(
"{}", data);
234 template <
typename ParseContext>
235 constexpr auto parse(ParseContext& ctx)
const {
245 template <
typename FormatContext>
247 std::string_view name =
"Unknown Type";
266 name =
"LongInteger";
272 name =
"BinaryBlobArray";
275 name =
"BooleanArray";
278 name =
"DatetimeArray";
281 name =
"DoubleArray";
284 name =
"IntegerArray";
287 name =
"LongIntegerArray";
290 name =
"StringArray";
294 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", name);
299 out << ASTARTE_NS_FORMAT::format(
"{}", typ);
308struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstarteDatastreamIndividual> {
314 template <
typename ParseContext>
315 constexpr auto parse(ParseContext& ctx)
const {
325 template <
typename FormatContext>
326 auto format(
const AstarteDeviceSdk::AstarteDatastreamIndividual& data, FormatContext& ctx)
const {
327 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", data.
get_value());
331inline std::ostream& operator<<(std::ostream& out,
333 out << ASTARTE_NS_FORMAT::format(
"{}", data);
341struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstarteDatastreamObject> {
347 template <
typename ParseContext>
348 constexpr auto parse(ParseContext& ctx)
const {
358 template <
typename FormatContext>
359 auto format(
const AstarteDeviceSdk::AstarteDatastreamObject& data, FormatContext& ctx)
const {
360 auto out = ctx.out();
361 out = ASTARTE_NS_FORMAT::format_to(out,
"{{");
366 out = ASTARTE_NS_FORMAT::format_to(out,
", ");
368 out = ASTARTE_NS_FORMAT::format_to(out, R
"("{}": {})", pair.first, pair.second);
372 out = ASTARTE_NS_FORMAT::format_to(out,
"}}");
377inline std::ostream& operator<<(std::ostream& out,
379 out << ASTARTE_NS_FORMAT::format(
"{}", data);
388struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstartePropertyIndividual> {
394 template <
typename ParseContext>
395 constexpr auto parse(ParseContext& ctx)
const {
405 template <
typename FormatContext>
406 auto format(
const AstarteDeviceSdk::AstartePropertyIndividual& data, FormatContext& ctx)
const {
408 return ASTARTE_NS_FORMAT::format_to(ctx.out(),
"{}", data.
get_value().value());
415inline std::ostream& operator<<(std::ostream& out,
417 out << ASTARTE_NS_FORMAT::format(
"{}", data);
431 template <
typename ParseContext>
432 constexpr auto parse(ParseContext& ctx)
const {
442 template <
typename FormatContext>
443 auto format(
const AstarteDeviceSdk::AstarteMessage& msg, FormatContext& ctx)
const {
444 auto out = ctx.out();
446 out = ASTARTE_NS_FORMAT::format_to(out,
"{{interface: {}, path: {}", msg.
get_interface(),
450 bool is_unset_prop =
false;
452 std::get_if<AstarteDeviceSdk::AstartePropertyIndividual>(&msg.
get_raw_data());
453 if (prop && !prop->get_value().has_value()) {
454 is_unset_prop =
true;
457 if (!is_unset_prop) {
458 out = ASTARTE_NS_FORMAT::format_to(out,
", value: ");
459 std::visit([&out](
const auto& arg) { out = ASTARTE_NS_FORMAT::format_to(out,
"{}", arg); },
463 return ASTARTE_NS_FORMAT::format_to(out,
"}}");
468 out << ASTARTE_NS_FORMAT::format(
"{}", msg);
476struct ASTARTE_NS_FORMAT::formatter<
AstarteDeviceSdk::AstarteStoredProperty> {
482 template <
typename ParseContext>
483 constexpr auto parse(ParseContext& ctx)
const {
493 template <
typename FormatContext>
494 auto format(
const AstarteDeviceSdk::AstarteStoredProperty& prop, FormatContext& ctx)
const {
495 return ASTARTE_NS_FORMAT::format_to(
496 ctx.out(),
"Interface: {} v{}, Path: {}, Ownership: {}, Value: {}",
503inline std::ostream& operator<<(std::ostream& out,
505 out << ASTARTE_NS_FORMAT::format(
"{}", prop);
Astarte data class, representing the basic Astarte types.
Definition data.hpp:39
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.
Astarte message class, represents a full message for/from Astarte.
Definition msg.hpp:25
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.
Representing data for a stored property.
Definition stored_property.hpp:23
auto get_ownership() const -> const AstarteOwnership &
Get the ownership contained within the object.
auto get_version_major() const -> int32_t
Get the major version within the object.
auto get_interface_name() const -> const std::string &
Get the interface name contained within the object.
auto get_path() const -> const std::string &
Get the path contained within the object.
auto get_value() const -> const 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:22
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
@ kDevice
Ownership is retained by the device.
Definition ownership.hpp:21
Contain utility functions for formatting data.
Definition formatter.hpp:35
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:91
void format_vector(OutputIt &out, const std::vector< T > &data)
Format a generic vector into a comma-separated list in brackets.
Definition formatter.hpp:138
void format_base64(OutputIt &out, const std::vector< uint8_t > &data)
Format a vector of bytes into a Base64 string literal.
Definition formatter.hpp:46
void format_data(OutputIt &out, const T &data)
Format a generic data type into an output iterator.
Definition formatter.hpp:116
Astarte object class and its related methods.
Ownership definitions for communication with Astarte.
Astarte stored property class and its related methods.
Types definitions for communication with Astarte.