5#ifndef ASTARTE_FORMATTER_H
6#define ASTARTE_FORMATTER_H
12#if ((defined(_MSVC_LANG) && _MSVC_LANG >= 202002L) || \
13 (!defined(_MSVC_LANG) && __cplusplus >= 202002L)) && \
14 (__has_include(<format>))
16namespace astarte_fmt = ::std;
18#include <spdlog/fmt/fmt.h>
22namespace astarte_fmt = ::fmt;
29#include "astarte_device_sdk/property.hpp"
46template <
typename OutputIt>
48 static constexpr std::string_view base64_chars =
49 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
50 "abcdefghijklmnopqrstuvwxyz"
54 const size_t len = data.size();
56 out = astarte_fmt::format_to(out,
"\"");
58 while (idx + 2 < len) {
59 const uint32_t chunk = (data[idx] << 16) | (data[idx + 1] << 8) | data[idx + 2];
60 out = astarte_fmt::format_to(out,
"{}{}{}{}", base64_chars[(chunk >> 18) & 0x3F],
61 base64_chars[(chunk >> 12) & 0x3F],
62 base64_chars[(chunk >> 6) & 0x3F], base64_chars[chunk & 0x3F]);
67 uint32_t chunk = data[idx] << 16;
69 chunk |= data[idx + 1] << 8;
72 out = astarte_fmt::format_to(out,
"{}{}", base64_chars[(chunk >> 18) & 0x3F],
73 base64_chars[(chunk >> 12) & 0x3F]);
75 out = astarte_fmt::format_to(out,
"{}=", base64_chars[(chunk >> 6) & 0x3F]);
77 out = astarte_fmt::format_to(out,
"==");
81 out = astarte_fmt::format_to(out,
"\"");
91template <
typename OutputIt>
92void format_timestamp(OutputIt& out,
const std::chrono::system_clock::time_point& data) {
93 out = astarte_fmt::format_to(out,
"\"");
94#if (__cplusplus >= 202002L) && (__has_include(<format>))
95 out = astarte_fmt::format_to(
97 astarte_fmt::format(
"{0:%F}T{0:%T}Z",
98 std::chrono::time_point_cast<std::chrono::milliseconds>(data)));
100 const std::time_t time = std::chrono::system_clock::to_time_t(data);
101 const std::tm utc_tm = *std::gmtime(&time);
102 std::stringstream stream;
103 stream << std::put_time(&utc_tm,
"%FT%T.000Z");
104 out = astarte_fmt::format_to(out,
"{}", stream.str());
106 out = astarte_fmt::format_to(out,
"\"");
116template <
typename OutputIt,
typename T>
118 if constexpr (std::is_same_v<T, bool>) {
119 astarte_fmt::format_to(out,
"{}", (data ?
"true" :
"false"));
120 }
else if constexpr (std::is_same_v<T, std::string>) {
121 astarte_fmt::format_to(out, R
"("{}")", data);
122 } else if constexpr (std::is_same_v<T, std::vector<uint8_t>>) {
124 }
else if constexpr (std::is_same_v<T, std::chrono::system_clock::time_point>) {
127 astarte_fmt::format_to(out,
"{}", data);
138template <
typename OutputIt,
typename T>
140 out = astarte_fmt::format_to(out,
"[");
141 for (
size_t i = 0; i < data.size(); ++i) {
143 if (i != data.size() - 1) {
144 out = astarte_fmt::format_to(out,
", ");
147 out = astarte_fmt::format_to(out,
"]");
166 template <
typename ParseContext>
167 constexpr auto parse(ParseContext& ctx)
const {
177 template <
typename FormatContext>
178 auto format(
const AstarteDeviceSdk::AstarteData& data, FormatContext& ctx)
const {
179 auto out = ctx.out();
181 if (std::holds_alternative<int32_t>(data.
get_raw_data())) {
182 out = astarte_fmt::format_to(out,
"{}", std::get<int32_t>(data.
get_raw_data()));
183 }
else if (std::holds_alternative<int64_t>(data.
get_raw_data())) {
184 out = astarte_fmt::format_to(out,
"{}", std::get<int64_t>(data.
get_raw_data()));
185 }
else if (std::holds_alternative<double>(data.
get_raw_data())) {
186 out = astarte_fmt::format_to(out,
"{}", std::get<double>(data.
get_raw_data()));
187 }
else if (std::holds_alternative<bool>(data.
get_raw_data())) {
188 auto s = (std::get<bool>(data.
get_raw_data()) ?
"true" :
"false");
189 out = astarte_fmt::format_to(out,
"{}", s);
190 }
else if (std::holds_alternative<std::string>(data.
get_raw_data())) {
191 out = astarte_fmt::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_fmt::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_fmt::format_to(ctx.out(),
"{}", name);
299 out << astarte_fmt::format(
"{}", typ);
308struct astarte_fmt::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_fmt::format_to(ctx.out(),
"{}", data.
get_value());
331inline std::ostream& operator<<(std::ostream& out,
333 out << astarte_fmt::format(
"{}", data);
348 template <
typename ParseContext>
349 constexpr auto parse(ParseContext& ctx)
const {
359 template <
typename FormatContext>
360 auto format(
const AstarteDeviceSdk::AstarteDatastreamObject& data, FormatContext& ctx)
const {
361 auto out = ctx.out();
362 out = astarte_fmt::format_to(out,
"{{");
367 out = astarte_fmt::format_to(out,
", ");
369 out = astarte_fmt::format_to(out, R
"("{}": {})", pair.first, pair.second);
373 out = astarte_fmt::format_to(out,
"}}");
378inline std::ostream& operator<<(std::ostream& out,
380 out << astarte_fmt::format(
"{}", data);
395 template <
typename ParseContext>
396 constexpr auto parse(ParseContext& ctx)
const {
406 template <
typename FormatContext>
407 auto format(
const AstarteDeviceSdk::AstartePropertyIndividual& data, FormatContext& ctx)
const {
409 return astarte_fmt::format_to(ctx.out(),
"{}", data.
get_value().value());
416inline std::ostream& operator<<(std::ostream& out,
418 out << astarte_fmt::format(
"{}", data);
432 template <
typename ParseContext>
433 constexpr auto parse(ParseContext& ctx)
const {
443 template <
typename FormatContext>
444 auto format(
const AstarteDeviceSdk::AstarteMessage& msg, FormatContext& ctx)
const {
445 auto out = ctx.out();
447 out = astarte_fmt::format_to(out,
"{{interface: {}, path: {}", msg.
get_interface(),
451 bool is_unset_prop =
false;
453 std::get_if<AstarteDeviceSdk::AstartePropertyIndividual>(&msg.
get_raw_data());
454 if (prop && !prop->get_value().has_value()) {
455 is_unset_prop =
true;
458 if (!is_unset_prop) {
459 out = astarte_fmt::format_to(out,
", value: ");
460 std::visit([&out](
const auto& arg) { out = astarte_fmt::format_to(out,
"{}", arg); },
464 return astarte_fmt::format_to(out,
"}}");
469 out << astarte_fmt::format(
"{}", msg);
483 template <
typename ParseContext>
484 constexpr auto parse(ParseContext& ctx)
const {
494 template <
typename FormatContext>
495 auto format(
const AstarteDeviceSdk::AstarteStoredProperty& prop, FormatContext& ctx)
const {
496 return astarte_fmt::format_to(
497 ctx.out(),
"Interface: {} v{}, Path: {}, Ownership: {}, Value: {}",
504inline std::ostream& operator<<(std::ostream& out,
506 out << astarte_fmt::format(
"{}", prop);
Astarte data class, representing the basic Astarte types.
Definition data.hpp:40
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:23
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:36
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:92
void format_vector(OutputIt &out, const std::vector< T > &data)
Format a generic vector into a comma-separated list in brackets.
Definition formatter.hpp:139
void format_base64(OutputIt &out, const std::vector< uint8_t > &data)
Format a vector of bytes into a Base64 string literal.
Definition formatter.hpp:47
void format_data(OutputIt &out, const T &data)
Format a generic data type into an output iterator.
Definition formatter.hpp:117
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.