blob: 8a9abe1477ef512ee94be92e8aa6784e8652f70a [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
96/** @brief Specialization of PackSingle for std::string
97 * represented as a UCSD-Pascal style string
98 */
99template <>
100struct PackSingle<std::string>
101{
James Feistf2998072019-04-03 11:54:52 -0700102 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700103 {
104 // check length first
105 uint8_t len;
106 if (t.length() > std::numeric_limits<decltype(len)>::max())
107 {
108 using namespace phosphor::logging;
109 log<level::ERR>("long string truncated on IPMI message pack");
110 return 1;
111 }
112 len = static_cast<uint8_t>(t.length());
113 PackSingle<uint8_t>::op(p, len);
114 p.append(t.c_str(), t.c_str() + t.length());
115 return 0;
116 }
117};
118
119/** @brief Specialization of PackSingle for fixed_uint_t types
120 */
121template <unsigned N>
122struct PackSingle<fixed_uint_t<N>>
123{
James Feistf2998072019-04-03 11:54:52 -0700124 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700125 {
126 size_t count = N;
127 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
128 uint64_t bits = t;
129 while (count > 0)
130 {
131 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
132 p.appendBits(appendCount, static_cast<uint8_t>(bits));
133 bits >>= CHAR_BIT;
134 count -= appendCount;
135 }
136 return 0;
137 }
138};
139
140/** @brief Specialization of PackSingle for bool. */
141template <>
142struct PackSingle<bool>
143{
James Feistf2998072019-04-03 11:54:52 -0700144 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700145 {
146 p.appendBits(1, b);
147 return 0;
148 }
149};
150
151/** @brief Specialization of PackSingle for std::bitset<N> */
152template <size_t N>
153struct PackSingle<std::bitset<N>>
154{
James Feistf2998072019-04-03 11:54:52 -0700155 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700156 {
157 size_t count = N;
158 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
159 unsigned long long bits = t.to_ullong();
160 while (count > 0)
161 {
162 size_t appendCount = std::min(count, size_t(CHAR_BIT));
163 p.appendBits(appendCount, static_cast<uint8_t>(bits));
164 bits >>= CHAR_BIT;
165 count -= appendCount;
166 }
167 return 0;
168 }
169};
170
Vernon Mauerybae91352019-04-03 12:11:08 -0700171/** @brief Specialization of PackSingle for std::optional<T> */
172template <typename T>
173struct PackSingle<std::optional<T>>
174{
175 static int op(Payload& p, const std::optional<T>& t)
176 {
177 int ret = 0;
178 if (t)
179 {
180 ret = PackSingle<T>::op(p, *t);
181 }
182 return ret;
183 }
184};
185
Vernon Mauerye7329c72018-10-08 12:05:16 -0700186/** @brief Specialization of PackSingle for std::array<T, N> */
187template <typename T, size_t N>
188struct PackSingle<std::array<T, N>>
189{
James Feistf2998072019-04-03 11:54:52 -0700190 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700191 {
192 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700193 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700194 {
195 int ret = PackSingle<T>::op(p, v);
196 if (ret)
197 {
198 break;
199 }
200 }
201 return ret;
202 }
203};
204
205/** @brief Specialization of PackSingle for std::vector<T> */
206template <typename T>
207struct PackSingle<std::vector<T>>
208{
James Feistf2998072019-04-03 11:54:52 -0700209 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700210 {
211 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700212 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700213 {
214 int ret = PackSingle<T>::op(p, v);
215 if (ret)
216 {
217 break;
218 }
219 }
220 return ret;
221 }
222};
223
224/** @brief Specialization of PackSingle for std::vector<uint8_t> */
225template <>
226struct PackSingle<std::vector<uint8_t>>
227{
James Feistf2998072019-04-03 11:54:52 -0700228 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700229 {
230 p.raw.reserve(p.raw.size() + t.size());
231 p.raw.insert(p.raw.end(), t.begin(), t.end());
232 return 0;
233 }
234};
235
James Feistf2998072019-04-03 11:54:52 -0700236/** @brief Specialization of PackSingle for std::variant<T, N> */
237template <typename... T>
238struct PackSingle<std::variant<T...>>
239{
240 static int op(Payload& p, const std::variant<T...>& v)
241 {
242 return std::visit(
243 [&p](const auto& arg) {
244 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
245 },
246 v);
247 }
248};
249
Vernon Mauerye7329c72018-10-08 12:05:16 -0700250} // namespace details
251
252} // namespace message
253
254} // namespace ipmi