blob: 4314ac19273fd113a89abcdb76feea58f7c87ad3 [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>
23#include <tuple>
24#include <utility>
25#include <vector>
26
27namespace ipmi
28{
29
30namespace message
31{
32
33namespace details
34{
35
36/**************************************
37 * ipmi return type helpers
38 **************************************/
39
40template <typename NumericType, size_t byteIndex = 0>
41void PackBytes(uint8_t* pointer, const NumericType& i)
42{
43 if constexpr (byteIndex < sizeof(NumericType))
44 {
45 *pointer = static_cast<uint8_t>(i >> (8 * byteIndex));
46 PackBytes<NumericType, byteIndex + 1>(pointer + 1, i);
47 }
48}
49
50template <typename NumericType, size_t byteIndex = 0>
51void PackBytesUnaligned(Payload& p, const NumericType& i)
52{
53 if constexpr (byteIndex < sizeof(NumericType))
54 {
55 p.appendBits(CHAR_BIT, static_cast<uint8_t>(i >> (8 * byteIndex)));
56 PackBytesUnaligned<NumericType, byteIndex + 1>(p, i);
57 }
58}
59
60/** @struct PackSingle
61 * @brief Utility to pack a single C++ element into a Payload
62 *
63 * User-defined types are expected to specialize this template in order to
64 * get their functionality.
65 *
66 * @tparam S - Type of element to pack.
67 */
68template <typename T>
69struct PackSingle
70{
71 /** @brief Do the operation to pack element.
72 *
73 * @param[in] p - Payload to pack into.
74 * @param[out] t - The reference to pack item into.
75 */
James Feistf2998072019-04-03 11:54:52 -070076 static int op(Payload& p, const T& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -070077 {
Vernon Mauery336405b2019-04-08 09:59:01 -070078 static_assert(std::is_integral_v<T>,
79 "Attempt to pack a type that has no IPMI pack operation");
Vernon Mauerye7329c72018-10-08 12:05:16 -070080 // if not on a byte boundary, must pack values LSbit/LSByte first
81 if (p.bitCount)
82 {
83 PackBytesUnaligned<T>(p, t);
84 }
85 else
86 {
87 // copy in bits to vector....
88 p.raw.resize(p.raw.size() + sizeof(T));
89 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
90 PackBytes<T>(out, t);
91 }
92 return 0;
93 }
94};
95
Vernon Mauery508c4572019-04-08 10:01:33 -070096/** @brief Specialization of PackSingle for std::tuple<T> */
97template <typename... T>
98struct PackSingle<std::tuple<T...>>
99{
100 static int op(Payload& p, const std::tuple<T...>& v)
101 {
102 return std::apply([&p](const T&... args) { return p.pack(args...); },
103 v);
104 }
105};
106
Vernon Mauerye7329c72018-10-08 12:05:16 -0700107/** @brief Specialization of PackSingle for std::string
108 * represented as a UCSD-Pascal style string
109 */
110template <>
111struct PackSingle<std::string>
112{
James Feistf2998072019-04-03 11:54:52 -0700113 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700114 {
115 // check length first
116 uint8_t len;
117 if (t.length() > std::numeric_limits<decltype(len)>::max())
118 {
119 using namespace phosphor::logging;
120 log<level::ERR>("long string truncated on IPMI message pack");
121 return 1;
122 }
123 len = static_cast<uint8_t>(t.length());
124 PackSingle<uint8_t>::op(p, len);
125 p.append(t.c_str(), t.c_str() + t.length());
126 return 0;
127 }
128};
129
130/** @brief Specialization of PackSingle for fixed_uint_t types
131 */
132template <unsigned N>
133struct PackSingle<fixed_uint_t<N>>
134{
James Feistf2998072019-04-03 11:54:52 -0700135 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700136 {
137 size_t count = N;
138 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
139 uint64_t bits = t;
140 while (count > 0)
141 {
142 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
143 p.appendBits(appendCount, static_cast<uint8_t>(bits));
144 bits >>= CHAR_BIT;
145 count -= appendCount;
146 }
147 return 0;
148 }
149};
150
151/** @brief Specialization of PackSingle for bool. */
152template <>
153struct PackSingle<bool>
154{
James Feistf2998072019-04-03 11:54:52 -0700155 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700156 {
157 p.appendBits(1, b);
158 return 0;
159 }
160};
161
162/** @brief Specialization of PackSingle for std::bitset<N> */
163template <size_t N>
164struct PackSingle<std::bitset<N>>
165{
James Feistf2998072019-04-03 11:54:52 -0700166 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700167 {
168 size_t count = N;
169 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
170 unsigned long long bits = t.to_ullong();
171 while (count > 0)
172 {
173 size_t appendCount = std::min(count, size_t(CHAR_BIT));
174 p.appendBits(appendCount, static_cast<uint8_t>(bits));
175 bits >>= CHAR_BIT;
176 count -= appendCount;
177 }
178 return 0;
179 }
180};
181
Vernon Mauerybae91352019-04-03 12:11:08 -0700182/** @brief Specialization of PackSingle for std::optional<T> */
183template <typename T>
184struct PackSingle<std::optional<T>>
185{
186 static int op(Payload& p, const std::optional<T>& t)
187 {
188 int ret = 0;
189 if (t)
190 {
191 ret = PackSingle<T>::op(p, *t);
192 }
193 return ret;
194 }
195};
196
Vernon Mauerye7329c72018-10-08 12:05:16 -0700197/** @brief Specialization of PackSingle for std::array<T, N> */
198template <typename T, size_t N>
199struct PackSingle<std::array<T, N>>
200{
James Feistf2998072019-04-03 11:54:52 -0700201 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700202 {
203 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700204 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700205 {
206 int ret = PackSingle<T>::op(p, v);
207 if (ret)
208 {
209 break;
210 }
211 }
212 return ret;
213 }
214};
215
216/** @brief Specialization of PackSingle for std::vector<T> */
217template <typename T>
218struct PackSingle<std::vector<T>>
219{
James Feistf2998072019-04-03 11:54:52 -0700220 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700221 {
222 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700223 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700224 {
225 int ret = PackSingle<T>::op(p, v);
226 if (ret)
227 {
228 break;
229 }
230 }
231 return ret;
232 }
233};
234
235/** @brief Specialization of PackSingle for std::vector<uint8_t> */
236template <>
237struct PackSingle<std::vector<uint8_t>>
238{
James Feistf2998072019-04-03 11:54:52 -0700239 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700240 {
241 p.raw.reserve(p.raw.size() + t.size());
242 p.raw.insert(p.raw.end(), t.begin(), t.end());
243 return 0;
244 }
245};
246
James Feistf2998072019-04-03 11:54:52 -0700247/** @brief Specialization of PackSingle for std::variant<T, N> */
248template <typename... T>
249struct PackSingle<std::variant<T...>>
250{
251 static int op(Payload& p, const std::variant<T...>& v)
252 {
253 return std::visit(
254 [&p](const auto& arg) {
255 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
256 },
257 v);
258 }
259};
260
Vernon Mauerye7329c72018-10-08 12:05:16 -0700261} // namespace details
262
263} // namespace message
264
265} // namespace ipmi