blob: b458af40b130d026ac1fb875bcdb49796d7b3be1 [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 {
78 // if not on a byte boundary, must pack values LSbit/LSByte first
79 if (p.bitCount)
80 {
81 PackBytesUnaligned<T>(p, t);
82 }
83 else
84 {
85 // copy in bits to vector....
86 p.raw.resize(p.raw.size() + sizeof(T));
87 uint8_t* out = p.raw.data() + p.raw.size() - sizeof(T);
88 PackBytes<T>(out, t);
89 }
90 return 0;
91 }
92};
93
94/** @brief Specialization of PackSingle for std::string
95 * represented as a UCSD-Pascal style string
96 */
97template <>
98struct PackSingle<std::string>
99{
James Feistf2998072019-04-03 11:54:52 -0700100 static int op(Payload& p, const std::string& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700101 {
102 // check length first
103 uint8_t len;
104 if (t.length() > std::numeric_limits<decltype(len)>::max())
105 {
106 using namespace phosphor::logging;
107 log<level::ERR>("long string truncated on IPMI message pack");
108 return 1;
109 }
110 len = static_cast<uint8_t>(t.length());
111 PackSingle<uint8_t>::op(p, len);
112 p.append(t.c_str(), t.c_str() + t.length());
113 return 0;
114 }
115};
116
117/** @brief Specialization of PackSingle for fixed_uint_t types
118 */
119template <unsigned N>
120struct PackSingle<fixed_uint_t<N>>
121{
James Feistf2998072019-04-03 11:54:52 -0700122 static int op(Payload& p, const fixed_uint_t<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700123 {
124 size_t count = N;
125 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
126 uint64_t bits = t;
127 while (count > 0)
128 {
129 size_t appendCount = std::min(count, static_cast<size_t>(CHAR_BIT));
130 p.appendBits(appendCount, static_cast<uint8_t>(bits));
131 bits >>= CHAR_BIT;
132 count -= appendCount;
133 }
134 return 0;
135 }
136};
137
138/** @brief Specialization of PackSingle for bool. */
139template <>
140struct PackSingle<bool>
141{
James Feistf2998072019-04-03 11:54:52 -0700142 static int op(Payload& p, const bool& b)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700143 {
144 p.appendBits(1, b);
145 return 0;
146 }
147};
148
149/** @brief Specialization of PackSingle for std::bitset<N> */
150template <size_t N>
151struct PackSingle<std::bitset<N>>
152{
James Feistf2998072019-04-03 11:54:52 -0700153 static int op(Payload& p, const std::bitset<N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700154 {
155 size_t count = N;
156 static_assert(N <= (details::bitStreamSize - CHAR_BIT));
157 unsigned long long bits = t.to_ullong();
158 while (count > 0)
159 {
160 size_t appendCount = std::min(count, size_t(CHAR_BIT));
161 p.appendBits(appendCount, static_cast<uint8_t>(bits));
162 bits >>= CHAR_BIT;
163 count -= appendCount;
164 }
165 return 0;
166 }
167};
168
Vernon Mauerybae91352019-04-03 12:11:08 -0700169/** @brief Specialization of PackSingle for std::optional<T> */
170template <typename T>
171struct PackSingle<std::optional<T>>
172{
173 static int op(Payload& p, const std::optional<T>& t)
174 {
175 int ret = 0;
176 if (t)
177 {
178 ret = PackSingle<T>::op(p, *t);
179 }
180 return ret;
181 }
182};
183
Vernon Mauerye7329c72018-10-08 12:05:16 -0700184/** @brief Specialization of PackSingle for std::array<T, N> */
185template <typename T, size_t N>
186struct PackSingle<std::array<T, N>>
187{
James Feistf2998072019-04-03 11:54:52 -0700188 static int op(Payload& p, const std::array<T, N>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700189 {
190 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700191 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700192 {
193 int ret = PackSingle<T>::op(p, v);
194 if (ret)
195 {
196 break;
197 }
198 }
199 return ret;
200 }
201};
202
203/** @brief Specialization of PackSingle for std::vector<T> */
204template <typename T>
205struct PackSingle<std::vector<T>>
206{
James Feistf2998072019-04-03 11:54:52 -0700207 static int op(Payload& p, const std::vector<T>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700208 {
209 int ret = 0;
James Feistf2998072019-04-03 11:54:52 -0700210 for (const auto& v : t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700211 {
212 int ret = PackSingle<T>::op(p, v);
213 if (ret)
214 {
215 break;
216 }
217 }
218 return ret;
219 }
220};
221
222/** @brief Specialization of PackSingle for std::vector<uint8_t> */
223template <>
224struct PackSingle<std::vector<uint8_t>>
225{
James Feistf2998072019-04-03 11:54:52 -0700226 static int op(Payload& p, const std::vector<uint8_t>& t)
Vernon Mauerye7329c72018-10-08 12:05:16 -0700227 {
228 p.raw.reserve(p.raw.size() + t.size());
229 p.raw.insert(p.raw.end(), t.begin(), t.end());
230 return 0;
231 }
232};
233
James Feistf2998072019-04-03 11:54:52 -0700234/** @brief Specialization of PackSingle for std::variant<T, N> */
235template <typename... T>
236struct PackSingle<std::variant<T...>>
237{
238 static int op(Payload& p, const std::variant<T...>& v)
239 {
240 return std::visit(
241 [&p](const auto& arg) {
242 return PackSingle<std::decay_t<decltype(arg)>>::op(p, arg);
243 },
244 v);
245 }
246};
247
Vernon Mauerye7329c72018-10-08 12:05:16 -0700248} // namespace details
249
250} // namespace message
251
252} // namespace ipmi