blob: 598e65077cab4fea4ef486ba63a111ed18dc2ac7 [file] [log] [blame]
Vernon Mauerye7329c72018-10-08 12:05:16 -07001/**
2 * Copyright © 2018 Intel Corporation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16#pragma once
17
18#include <array>
19#include <ipmid/message/types.hpp>
20#include <memory>
Vernon Mauerybae91352019-04-03 12:11:08 -070021#include <optional>
Vernon Mauerye7329c72018-10-08 12:05:16 -070022#include <phosphor-logging/log.hpp>
William A. Kennington IIIe2aec262019-04-24 14:44:26 -070023#include <string_view>
Vernon Mauerye7329c72018-10-08 12:05:16 -070024#include <tuple>
25#include <utility>
Alexander Amelkin00b096d2019-04-15 15:11:03 +030026#include <variant>
Vernon Mauerye7329c72018-10-08 12:05:16 -070027#include <vector>
28
29namespace ipmi
30{
31
32namespace message
33{
34
35namespace details
36{
37
38/**************************************
39 * ipmi return type helpers
40 **************************************/
41
42template <typename NumericType, size_t byteIndex = 0>
43void PackBytes(uint8_t* pointer, const NumericType& i)
44{
45 if constexpr (byteIndex < sizeof(NumericType))
46 {
47 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
48 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
49 }
50}
51
52template <typename NumericType, size_t byteIndex = 0>
53void PackBytesUnaligned(Payload& p, const NumericType& i)
54{
55 if constexpr (byteIndex < sizeof(NumericType))
56 {
57 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
58 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
59 }
60}
61
62/** @struct PackSingle
63 * @brief Utility to pack a single C++ element into a Payload
64 *
65 * User-defined types are expected to specialize this template in order to
66 * get their functionality.
67 *
68 * @tparam S - Type of element to pack.
69 */
70template <typename T>
71struct PackSingle
72{
73 /** @brief Do the operation to pack element.
74 *
75 * @param[in] p - Payload to pack into.
76 * @param[out] t - The reference to pack item into.
77 */
James Feistf2998072019-04-03 11:54:52 -070078 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070079 {
Vernon Mauery336405b2019-04-08 09:59:01 -070080 static_assert(std::is_integral_v<T>,
81 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070082 // if not on a byte boundary, must pack values LSbit/LSByte first
83 if (p.bitCount)
84 {
85 PackBytesUnaligned<T>(p, t);
86 }
87 else
88 {
89 // copy in bits to vector....
90 p.raw.resize(p.raw.size() + sizeof(T));
91 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
92 PackBytes<T>(out, t);
93 }
94 return 0;
95 }
96};
97
Vernon Mauery508c4572019-04-08 10:01:33 -070098/** @brief Specialization of PackSingle for std::tuple<T> */
99template <typename... T>
100struct PackSingle<std::tuple<T...>>
101{
102 static int op(Payload& p, const std::tuple<T...>& v)
103 {
104 return std::apply([&p](const T&... args) { return p.pack(args...); },
105 v);
106 }
107};
108
Vernon Mauerye7329c72018-10-08 12:05:16 -0700109/** @brief Specialization of PackSingle for std::string
110 * represented as a UCSD-Pascal style string
111 */
112template <>
113struct PackSingle<std::string>
114{
James Feistf2998072019-04-03 11:54:52 -0700115 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700116 {
117 // check length first
118 uint8_t len;
119 if (t.length() > std::numeric_limits<decltype(len)>::max())
120 {
121 using namespace phosphor::logging;
122 log<level::ERR>("long string truncated on IPMI message pack");
123 return 1;
124 }
125 len = static_cast<uint8_t>(t.length());
126 PackSingle<uint8_t>::op(p, len);
127 p.append(t.c_str(), t.c_str() + t.length());
128 return 0;
129 }
130};
131
132/** @brief Specialization of PackSingle for fixed_uint_t types
133 */
134template <unsigned N>
135struct PackSingle<fixed_uint_t<N>>
136{
James Feistf2998072019-04-03 11:54:52 -0700137 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700138 {
139 size_t count = N;
140 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
141 uint64_t bits = t;
142 while (count > 0)
143 {
144 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
145 p.appendBits(appendCount, static_cast<uint8_t>(bits));
146 bits >>= CHAR_BIT;
147 count -= appendCount;
148 }
149 return 0;
150 }
151};
152
153/** @brief Specialization of PackSingle for bool. */
154template <>
155struct PackSingle<bool>
156{
James Feistf2998072019-04-03 11:54:52 -0700157 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700158 {
159 p.appendBits(1, b);
160 return 0;
161 }
162};
163
164/** @brief Specialization of PackSingle for std::bitset<N> */
165template <size_t N>
166struct PackSingle<std::bitset<N>>
167{
James Feistf2998072019-04-03 11:54:52 -0700168 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700169 {
170 size_t count = N;
171 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
172 unsigned long long bits = t.to_ullong();
173 while (count > 0)
174 {
175 size_t appendCount = std::min(count, size_t(CHAR_BIT));
176 p.appendBits(appendCount, static_cast<uint8_t>(bits));
177 bits >>= CHAR_BIT;
178 count -= appendCount;
179 }
180 return 0;
181 }
182};
183
Vernon Mauerybae91352019-04-03 12:11:08 -0700184/** @brief Specialization of PackSingle for std::optional<T> */
185template <typename T>
186struct PackSingle<std::optional<T>>
187{
188 static int op(Payload& p, const std::optional<T>& t)
189 {
190 int ret = 0;
191 if (t)
192 {
193 ret = PackSingle<T>::op(p, *t);
194 }
195 return ret;
196 }
197};
198
Vernon Mauerye7329c72018-10-08 12:05:16 -0700199/** @brief Specialization of PackSingle for std::array<T, N> */
200template <typename T, size_t N>
201struct PackSingle<std::array<T, N>>
202{
James Feistf2998072019-04-03 11:54:52 -0700203 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700204 {
205 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700206 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700207 {
208 int ret = PackSingle<T>::op(p, v);
209 if (ret)
210 {
211 break;
212 }
213 }
214 return ret;
215 }
216};
217
218/** @brief Specialization of PackSingle for std::vector<T> */
219template <typename T>
220struct PackSingle<std::vector<T>>
221{
James Feistf2998072019-04-03 11:54:52 -0700222 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700223 {
224 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700225 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700226 {
227 int ret = PackSingle<T>::op(p, v);
228 if (ret)
229 {
230 break;
231 }
232 }
233 return ret;
234 }
235};
236
237/** @brief Specialization of PackSingle for std::vector<uint8_t> */
238template <>
239struct PackSingle<std::vector<uint8_t>>
240{
James Feistf2998072019-04-03 11:54:52 -0700241 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700242 {
William A. Kennington III906e0f82019-04-24 14:44:03 -0700243 if (p.bitCount != 0)
244 {
245 return 1;
246 }
Vernon Mauerye7329c72018-10-08 12:05:16 -0700247 p.raw.reserve(p.raw.size() + t.size());
248 p.raw.insert(p.raw.end(), t.begin(), t.end());
249 return 0;
250 }
251};
252
William A. Kennington IIIe2aec262019-04-24 14:44:26 -0700253/** @brief Specialization of PackSingle for std::string_view */
254template <>
255struct PackSingle<std::string_view>
256{
257 static int op(Payload& p, const std::string_view& t)
258 {
259 if (p.bitCount != 0)
260 {
261 return 1;
262 }
263 p.raw.reserve(p.raw.size() + t.size());
264 p.raw.insert(p.raw.end(), t.begin(), t.end());
265 return 0;
266 }
267};
268
James Feistf2998072019-04-03 11:54:52 -0700269/** @brief Specialization of PackSingle for std::variant<T, N> */
270template <typename... T>
271struct PackSingle<std::variant<T...>>
272{
273 static int op(Payload& p, const std::variant<T...>& v)
274 {
275 return std::visit(
276 [&p](const auto& arg) {
277 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
278 },
279 v);
280 }
281};
282
William A. Kennington IIIe15e53e2019-04-24 14:45:20 -0700283/** @brief Specialization of PackSingle for Payload */
284template <>
285struct PackSingle<Payload>
286{
287 static int op(Payload& p, const Payload& t)
288 {
289 if (p.bitCount != 0 || t.bitCount != 0)
290 {
291 return 1;
292 }
293 p.raw.reserve(p.raw.size() + t.raw.size());
294 p.raw.insert(p.raw.end(), t.raw.begin(), t.raw.end());
295 return 0;
296 }
297};
298
Vernon Mauerye7329c72018-10-08 12:05:16 -0700299} // namespace details
300
301} // namespace message
302
303} // namespace ipmi