Clio  develop
The XRP Ledger API server.
Loading...
Searching...
No Matches
Tuple.hpp
1//------------------------------------------------------------------------------
2/*
3 This file is part of clio: https://github.com/XRPLF/clio
4 Copyright (c) 2023, the clio developers.
5
6 Permission to use, copy, modify, and distribute this software for any
7 purpose with or without fee is hereby granted, provided that the above
8 copyright notice and this permission notice appear in all copies.
9
10 THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17*/
18//==============================================================================
19
20#pragma once
21
22#include "data/cassandra/impl/ManagedObject.hpp"
23#include "util/UnsupportedType.hpp"
24
25#include <cassandra.h>
26#include <xrpl/basics/base_uint.h>
27
28#include <cstddef>
29#include <cstdint>
30#include <functional>
31#include <stdexcept>
32#include <string>
33#include <string_view>
34#include <tuple>
35#include <type_traits>
36
37namespace data::cassandra::impl {
38
39class Tuple : public ManagedObject<CassTuple> {
40 static constexpr auto kDELETER = [](CassTuple* ptr) { cass_tuple_free(ptr); };
41
42public:
43 /* implicit */ Tuple(CassTuple* ptr);
44
45 template <typename... Types>
46 explicit Tuple(std::tuple<Types...>&& value)
47 : ManagedObject{cass_tuple_new(std::tuple_size<std::tuple<Types...>>{}), kDELETER}
48 {
49 std::apply(std::bind_front(&Tuple::bind<Types...>, this), std::move(value));
50 }
51
52 template <typename... Args>
53 void
54 bind(Args&&... args) const
55 {
56 std::size_t idx = 0;
57 (this->bindAt<Args>(idx++, std::forward<Args>(args)), ...);
58 }
59
60 template <typename Type>
61 void
62 bindAt(std::size_t const idx, Type&& value) const
63 {
64 using std::to_string;
65 auto throwErrorIfNeeded = [idx](CassError rc, std::string_view label) {
66 if (rc != CASS_OK) {
67 auto const tag = '[' + std::string{label} + ']';
68 throw std::logic_error(
69 tag + " at idx " + to_string(idx) + ": " + cass_error_desc(rc)
70 );
71 }
72 };
73
74 using DecayedType = std::decay_t<Type>;
75
76 if constexpr (std::is_same_v<DecayedType, bool>) {
77 auto const rc = cass_tuple_set_bool(*this, idx, value ? cass_true : cass_false);
78 throwErrorIfNeeded(rc, "Bind bool");
79 }
80 // clio only uses bigint (int64_t) so we convert any incoming type
81 else if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
82 auto const rc = cass_tuple_set_int64(*this, idx, std::forward<Type>(value));
83 throwErrorIfNeeded(rc, "Bind int64");
84 } else if constexpr (std::is_same_v<DecayedType, ripple::uint256>) {
85 auto const rc = cass_tuple_set_bytes(
86 *this,
87 idx,
88 static_cast<cass_byte_t const*>(static_cast<unsigned char const*>(value.data())),
89 value.size()
90 );
91 throwErrorIfNeeded(rc, "Bind ripple::uint256");
92 } else {
93 // type not supported for binding
94 static_assert(util::Unsupported<DecayedType>);
95 }
96 }
97};
98
99class TupleIterator : public ManagedObject<CassIterator> {
100public:
101 /* implicit */ TupleIterator(CassIterator* ptr);
102
103 [[nodiscard]] static TupleIterator
104 fromTuple(CassValue const* value);
105
106 template <typename... Types>
107 [[nodiscard]] std::tuple<Types...>
108 extract() const
109 {
110 return {extractNext<Types>()...};
111 }
112
113private:
114 template <typename Type>
115 Type
116 extractNext() const
117 {
118 using std::to_string;
119 Type output;
120
121 if (not cass_iterator_next(*this))
122 throw std::logic_error("Could not extract next value from tuple iterator");
123
124 auto throwErrorIfNeeded = [](CassError rc, std::string_view label) {
125 if (rc != CASS_OK) {
126 auto const tag = '[' + std::string{label} + ']';
127 throw std::logic_error(tag + ": " + cass_error_desc(rc));
128 }
129 };
130
131 using DecayedType = std::decay_t<Type>;
132
133 // clio only uses bigint (int64_t) so we convert any incoming type
134 if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
135 int64_t out = 0;
136 auto const rc = cass_value_get_int64(cass_iterator_get_value(*this), &out);
137 throwErrorIfNeeded(rc, "Extract int64 from tuple");
138 output = static_cast<DecayedType>(out);
139 } else {
140 // type not supported for extraction
141 static_assert(util::Unsupported<DecayedType>);
142 }
143
144 return output;
145 }
146};
147
148} // namespace data::cassandra::impl
static constexpr bool Unsupported
used for compile time checking of unsupported types
Definition UnsupportedType.hpp:26