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(tag + " at idx " + to_string(idx) + ": " + cass_error_desc(rc));
69 }
70 };
71
72 using DecayedType = std::decay_t<Type>;
73
74 if constexpr (std::is_same_v<DecayedType, bool>) {
75 auto const rc = cass_tuple_set_bool(*this, idx, value ? cass_true : cass_false);
76 throwErrorIfNeeded(rc, "Bind bool");
77 }
78 // clio only uses bigint (int64_t) so we convert any incoming type
79 else if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
80 auto const rc = cass_tuple_set_int64(*this, idx, std::forward<Type>(value));
81 throwErrorIfNeeded(rc, "Bind int64");
82 } else if constexpr (std::is_same_v<DecayedType, ripple::uint256>) {
83 auto const rc = cass_tuple_set_bytes(
84 *this,
85 idx,
86 static_cast<cass_byte_t const*>(static_cast<unsigned char const*>(value.data())),
87 value.size()
88 );
89 throwErrorIfNeeded(rc, "Bind ripple::uint256");
90 } else {
91 // type not supported for binding
92 static_assert(util::Unsupported<DecayedType>);
93 }
94 }
95};
96
97class TupleIterator : public ManagedObject<CassIterator> {
98public:
99 /* implicit */ TupleIterator(CassIterator* ptr);
100
101 [[nodiscard]] static TupleIterator
102 fromTuple(CassValue const* value);
103
104 template <typename... Types>
105 [[nodiscard]] std::tuple<Types...>
106 extract() const
107 {
108 return {extractNext<Types>()...};
109 }
110
111private:
112 template <typename Type>
113 Type
114 extractNext() const
115 {
116 using std::to_string;
117 Type output;
118
119 if (not cass_iterator_next(*this))
120 throw std::logic_error("Could not extract next value from tuple iterator");
121
122 auto throwErrorIfNeeded = [](CassError rc, std::string_view label) {
123 if (rc != CASS_OK) {
124 auto const tag = '[' + std::string{label} + ']';
125 throw std::logic_error(tag + ": " + cass_error_desc(rc));
126 }
127 };
128
129 using DecayedType = std::decay_t<Type>;
130
131 // clio only uses bigint (int64_t) so we convert any incoming type
132 if constexpr (std::is_convertible_v<DecayedType, int64_t>) {
133 int64_t out = 0;
134 auto const rc = cass_value_get_int64(cass_iterator_get_value(*this), &out);
135 throwErrorIfNeeded(rc, "Extract int64 from tuple");
136 output = static_cast<DecayedType>(out);
137 } else {
138 // type not supported for extraction
139 static_assert(util::Unsupported<DecayedType>);
140 }
141
142 return output;
143 }
144};
145
146} // namespace data::cassandra::impl
Definition ManagedObject.hpp:28
Definition Tuple.hpp:39
static constexpr bool Unsupported
used for compile time checking of unsupported types
Definition UnsupportedType.hpp:26