27 bool oneLine =
false) {
28 if (
auto *uintType =
dynamic_cast<const esi::UIntType *
>(type)) {
29 os <<
"uint" << uintType->getBitWidth();
30 }
else if (
auto *sintType =
dynamic_cast<const esi::SIntType *
>(type)) {
31 os <<
"sint" << sintType->getBitWidth();
32 }
else if (
auto *bitsType =
dynamic_cast<const esi::BitsType *
>(type)) {
33 os <<
"bits" << bitsType->getBitWidth();
38 }
else if (
auto *structType =
dynamic_cast<const esi::StructType *
>(type)) {
40 const auto &fields = structType->getFields();
41 for (
size_t i = 0; i < fields.size(); ++i) {
43 os << std::endl << std::string(level + 2,
' ');
46 const auto &[name, fieldType] = fields[i];
48 dumpType(os, fieldType, level + 1, oneLine);
49 if (i < fields.size() - 1)
53 os << std::endl << std::string(level,
' ');
55 }
else if (
auto *arrayType =
dynamic_cast<const esi::ArrayType *
>(type)) {
56 dumpType(os, arrayType->getElementType(), level + 1, oneLine);
57 os <<
"[" << arrayType->getSize() <<
"]";
58 }
else if (
auto *channelType =
dynamic_cast<const esi::ChannelType *
>(type)) {
60 dumpType(os, channelType->getInner(), level + 1, oneLine);
62 }
else if (
auto *bundleType =
dynamic_cast<const esi::BundleType *
>(type)) {
64 const auto &channels = bundleType->getChannels();
65 for (
size_t i = 0; i < channels.size(); ++i) {
67 os << std::endl << std::string(level + 2,
' ');
70 const auto &[name, direction, fieldType] = channels[i];
73 dumpType(os, fieldType, level + 1, oneLine);
74 if (i < channels.size() - 1)
78 os << std::endl << std::string(level,
' ');
82 }
else if (
auto *windowType =
dynamic_cast<const esi::WindowType *
>(type)) {
84 dumpType(os, windowType->getIntoType(), level + 1, oneLine);
86 }
else if (
auto *listType =
dynamic_cast<const esi::ListType *
>(type)) {
88 dumpType(os, listType->getElementType(), level + 1, oneLine);
97 dumpType(os,
this, oneLine ? 0 : 0, oneLine);
102 std::stringstream ss;
107std::pair<const Type *, BundleType::Direction>
109 for (
auto [channelName, dir, type] :
channels)
110 if (channelName == name)
111 return std::make_pair(type, dir);
112 throw std::runtime_error(
113 std::format(
"Channel '{}' not found in bundle", name));
130 if (!obj.has_value())
134 std::any_cast<std::nullptr_t>(obj);
136 }
catch (
const std::bad_any_cast &) {
137 throw std::runtime_error(
138 std::format(
"void type must be represented by empty std::any or "
139 "nullptr, but got {}",
145 if (data.width() < 8)
146 throw std::runtime_error(
"void type cannot be represented by empty data");
149 if (std::ranges::any_of(value, [](
auto b) {
return b; }))
150 throw std::runtime_error(std::format(
"void type byte must be 0, got {:b}",
166 auto data = std::any_cast<std::vector<uint8_t>>(obj);
167 size_t expectedSize = (
getWidth() + 7) / 8;
168 if (data.size() != expectedSize) {
169 throw std::runtime_error(
"wrong size: expected " +
170 std::to_string(expectedSize) +
" bytes, got " +
171 std::to_string(data.size()));
173 }
catch (
const std::bad_any_cast &) {
174 throw std::runtime_error(std::format(
175 "must be std::vector<uint8_t>, but got {}", obj.type().name()));
181 auto bytes = std::any_cast<std::vector<uint8_t>>(obj);
187 if (data.width() < w)
188 throw std::runtime_error(std::format(
"Insufficient data for bits type. "
189 " Expected {} bits, got {} bits",
202 const std::type_info &type = obj.type();
204 if (type ==
typeid(int64_t))
205 return Int(std::any_cast<int64_t>(obj), widthHint);
206 if (type ==
typeid(int32_t))
207 return Int(
static_cast<int64_t
>(std::any_cast<int32_t>(obj)), widthHint);
208 if (type ==
typeid(int16_t))
209 return Int(
static_cast<int64_t
>(std::any_cast<int16_t>(obj)), widthHint);
210 if (type ==
typeid(int8_t))
211 return Int(
static_cast<int64_t
>(std::any_cast<int8_t>(obj)), widthHint);
213 return std::any_cast<Int>(obj);
215 throw std::bad_any_cast();
221 const std::type_info &type = obj.type();
223 if (type ==
typeid(uint64_t))
224 return UInt(std::any_cast<uint64_t>(obj), widthHint);
225 if (type ==
typeid(uint32_t))
226 return UInt(
static_cast<uint64_t
>(std::any_cast<uint32_t>(obj)), widthHint);
227 if (type ==
typeid(uint16_t))
228 return UInt(
static_cast<uint64_t
>(std::any_cast<uint16_t>(obj)), widthHint);
229 if (type ==
typeid(uint8_t))
230 return UInt(
static_cast<uint64_t
>(std::any_cast<uint8_t>(obj)), widthHint);
232 return std::any_cast<UInt>(obj);
234 throw std::bad_any_cast();
240 }
catch (
const std::exception &e) {
241 throw std::runtime_error(std::format(
242 "Unable to convert provided object to a {}-bit wide Int: {}",
250 throw std::runtime_error(
251 std::format(
"Int width mismatch for SIntType serialize. Expected {} "
260 if (data.width() < w)
261 throw std::runtime_error(std::format(
262 "Insufficient data for sint type. Expected {} bits, got {} bits", w,
264 Int val(data.slice(0, w));
266 return std::any(val);
272 }
catch (
const std::exception &e) {
273 throw std::runtime_error(std::format(
274 "Unable to convert provided object to a {}-bit wide UInt: {}",
282 throw std::runtime_error(std::format(
283 "UInt width mismatch for UIntType serialize. Expected {} bits, got {} "
291 if (data.width() < w)
292 throw std::runtime_error(std::format(
293 "Insufficient data for uint type. Expected {} bits, got {} bits", w,
295 UInt val(data.slice(0, w));
297 return std::any(val);
302 auto structData = std::any_cast<std::map<std::string, std::any>>(obj);
304 if (structData.size() !=
fields.size()) {
305 throw std::runtime_error(std::format(
"struct has {} fields, expected {}",
306 structData.size(),
fields.size()));
309 for (
const auto &[fieldName, fieldType] :
fields) {
310 auto it = structData.find(fieldName);
311 if (it == structData.end())
312 throw std::runtime_error(std::format(
"missing field '{}'", fieldName));
315 fieldType->ensureValid(it->second);
316 }
catch (
const std::runtime_error &e) {
317 throw std::runtime_error(
318 std::format(
"invalid field '{}': {}", fieldName, e.what()));
321 }
catch (
const std::bad_any_cast &) {
322 throw std::runtime_error(
323 std::format(
"must be std::map<std::string, std::any>, but got {}",
330 auto structData = std::any_cast<std::map<std::string, std::any>>(obj);
332 auto handleField = [&](
const std::pair<std::string, const Type *> &f) {
333 const auto &name = f.first;
334 const Type *ty = f.second;
335 auto fieldData = ty->
serialize(structData.at(name));
336 out <<= fieldData.
width();
340 for (
const auto &f :
fields)
343 for (
auto it =
fields.rbegin(); it !=
fields.rend(); ++it)
350 std::map<std::string, std::any> result;
351 auto consumeField = [&](
const std::pair<std::string, const Type *> &f) {
352 const auto &name = f.first;
353 const Type *ty = f.second;
357 for (
auto it =
fields.rbegin(); it !=
fields.rend(); ++it)
360 for (
const auto &f :
fields)
363 return std::any(result);
368 auto arrayData = std::any_cast<std::vector<std::any>>(obj);
370 if (arrayData.size() !=
size) {
371 throw std::runtime_error(std::format(
"array has {} elements, expected {}",
372 arrayData.size(),
size));
375 for (
size_t i = 0; i < arrayData.size(); ++i) {
378 }
catch (
const std::runtime_error &e) {
379 throw std::runtime_error(
380 std::format(
"invalid element {}: {}", i, e.what()));
383 }
catch (
const std::bad_any_cast &) {
384 throw std::runtime_error(std::format(
385 "must be std::vector<std::any>, but got {}", obj.type().name()));
391 auto arrayData = std::any_cast<std::vector<std::any>>(obj);
393 auto handleElem = [&](
const std::any &elem) {
395 out <<= elemData.
width();
399 for (
const auto &e : arrayData)
402 for (
auto it = arrayData.rbegin(); it != arrayData.rend(); ++it)
409 std::vector<std::any> result;
410 result.reserve(
size);
411 for (uint64_t i = 0; i <
size; ++i) {
413 result.push_back(value);
416 std::reverse(result.begin(), result.end());
417 return std::any(result);
The "any" type is a special type which can be used to represent any type, as identified by the type i...
Arrays have a compile time specified (static) size and an element type.
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
uint64_t getWidth() const
A lightweight, non-owning bit vector view backed by a byte array span.
std::span< const byte > getSpan() const
Return a handle to the underlying span.
Bits are just an array of bits.
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
Bundles represent a collection of channels.
std::pair< const Type *, Direction > findChannel(std::string name) const
Channels are the basic communication primitives.
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
Lists represent variable-length sequences of elements of a single type.
A mutable bit vector that owns its underlying storage.
std::vector< uint8_t > takeStorage()
Return and transfer ownership of the underlying storage.
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
Structs are an ordered collection of fields, each with a name and a type.
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
Root class of the ESI type system.
virtual void ensureValid(const std::any &obj) const
Ensure that a std::any object is valid for this type.
std::string toString(bool oneLine=false) const
virtual std::any deserialize(BitVector &data) const
Deserialize from a BitVector stream (LSB-first).
virtual MutableBitVector serialize(const std::any &obj) const
Serialize an object to a MutableBitVector (LSB-first stream).
void dump(std::ostream &os, bool oneLine=false) const
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
The "void" type is a special type which can be used to represent no type.
std::any deserialize(BitVector &data) const override
Deserialize from a BitVector stream (LSB-first).
void ensureValid(const std::any &obj) const override
Ensure that a std::any object is valid for this type.
MutableBitVector serialize(const std::any &obj) const override
Serialize an object to a MutableBitVector (LSB-first stream).
Windows represent a fixed-size sliding window over a stream of data.
static UInt getUIntLikeFromAny(const std::any &obj, unsigned widthHint)
static Int getIntLikeFromAny(const std::any &obj, unsigned widthHint)
static void dumpType(std::ostream &os, const esi::Type *type, int level=0, bool oneLine=false)