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