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();
39 os << aliasType->getName();
40 }
else if (
auto *structType =
dynamic_cast<const esi::StructType *
>(type)) {
42 const auto &fields = structType->getFields();
43 for (
size_t i = 0; i < fields.size(); ++i) {
45 os << std::endl << std::string(level + 2,
' ');
48 const auto &[name, fieldType] = fields[i];
50 dumpType(os, fieldType, level + 1, oneLine);
51 if (i < fields.size() - 1)
55 os << std::endl << std::string(level,
' ');
57 }
else if (
auto *arrayType =
dynamic_cast<const esi::ArrayType *
>(type)) {
58 dumpType(os, arrayType->getElementType(), level + 1, oneLine);
59 os <<
"[" << arrayType->getSize() <<
"]";
60 }
else if (
auto *channelType =
dynamic_cast<const esi::ChannelType *
>(type)) {
62 dumpType(os, channelType->getInner(), level + 1, oneLine);
64 }
else if (
auto *bundleType =
dynamic_cast<const esi::BundleType *
>(type)) {
66 const auto &channels = bundleType->getChannels();
67 for (
size_t i = 0; i < channels.size(); ++i) {
69 os << std::endl << std::string(level + 2,
' ');
72 const auto &[name, direction, fieldType] = channels[i];
75 dumpType(os, fieldType, level + 1, oneLine);
76 if (i < channels.size() - 1)
80 os << std::endl << std::string(level,
' ');
84 }
else if (
auto *windowType =
dynamic_cast<const esi::WindowType *
>(type)) {
86 dumpType(os, windowType->getIntoType(), level + 1, oneLine);
88 }
else if (
auto *unionType =
dynamic_cast<const esi::UnionType *
>(type)) {
90 const auto &fields = unionType->getFields();
91 for (
size_t i = 0; i < fields.size(); ++i) {
93 os << std::endl << std::string(level + 2,
' ');
96 const auto &[name, fieldType] = fields[i];
98 dumpType(os, fieldType, level + 1, oneLine);
99 if (i < fields.size() - 1)
103 os << std::endl << std::string(level,
' ');
105 }
else if (
auto *listType =
dynamic_cast<const esi::ListType *
>(type)) {
107 dumpType(os, listType->getElementType(), level + 1, oneLine);
116 dumpType(os,
this, oneLine ? 0 : 0, oneLine);
121 std::stringstream ss;
126std::pair<const Type *, BundleType::Direction>
128 for (
auto [channelName, dir, type] :
channels)
129 if (channelName == name)
130 return std::make_pair(type, dir);
131 throw std::runtime_error(
132 std::format(
"Channel '{}' not found in bundle", name));
149 if (!obj.has_value())
153 std::any_cast<std::nullptr_t>(obj);
155 }
catch (
const std::bad_any_cast &) {
156 throw std::runtime_error(
157 std::format(
"void type must be represented by empty std::any or "
158 "nullptr, but got {}",
191 auto data = std::any_cast<std::vector<uint8_t>>(obj);
192 size_t expectedSize = (
getWidth() + 7) / 8;
193 if (data.size() != expectedSize) {
194 throw std::runtime_error(
"wrong size: expected " +
195 std::to_string(expectedSize) +
" bytes, got " +
196 std::to_string(data.size()));
198 }
catch (
const std::bad_any_cast &) {
199 throw std::runtime_error(std::format(
200 "must be std::vector<uint8_t>, but got {}", obj.type().name()));
206 auto bytes = std::any_cast<std::vector<uint8_t>>(obj);
212 if (data.width() < w)
213 throw std::runtime_error(std::format(
"Insufficient data for bits type. "
214 " Expected {} bits, got {} bits",
227 const std::type_info &type = obj.type();
229 if (type ==
typeid(int64_t))
230 return Int(std::any_cast<int64_t>(obj), widthHint);
231 if (type ==
typeid(int32_t))
232 return Int(
static_cast<int64_t
>(std::any_cast<int32_t>(obj)), widthHint);
233 if (type ==
typeid(int16_t))
234 return Int(
static_cast<int64_t
>(std::any_cast<int16_t>(obj)), widthHint);
235 if (type ==
typeid(int8_t))
236 return Int(
static_cast<int64_t
>(std::any_cast<int8_t>(obj)), widthHint);
238 return std::any_cast<Int>(obj);
240 throw std::bad_any_cast();
246 const std::type_info &type = obj.type();
248 if (type ==
typeid(uint64_t))
249 return UInt(std::any_cast<uint64_t>(obj), widthHint);
250 if (type ==
typeid(uint32_t))
251 return UInt(
static_cast<uint64_t
>(std::any_cast<uint32_t>(obj)), widthHint);
252 if (type ==
typeid(uint16_t))
253 return UInt(
static_cast<uint64_t
>(std::any_cast<uint16_t>(obj)), widthHint);
254 if (type ==
typeid(uint8_t))
255 return UInt(
static_cast<uint64_t
>(std::any_cast<uint8_t>(obj)), widthHint);
257 return std::any_cast<UInt>(obj);
259 throw std::bad_any_cast();
265 }
catch (
const std::exception &e) {
266 throw std::runtime_error(std::format(
267 "Unable to convert provided object to a {}-bit wide Int: {}",
275 throw std::runtime_error(
276 std::format(
"Int width mismatch for SIntType serialize. Expected {} "
285 if (data.width() < w)
286 throw std::runtime_error(std::format(
287 "Insufficient data for sint type. Expected {} bits, got {} bits", w,
289 Int val(data.slice(0, w));
291 return std::any(val);
297 }
catch (
const std::exception &e) {
298 throw std::runtime_error(std::format(
299 "Unable to convert provided object to a {}-bit wide UInt: {}",
307 throw std::runtime_error(std::format(
308 "UInt width mismatch for UIntType serialize. Expected {} bits, got {} "
316 if (data.width() < w)
317 throw std::runtime_error(std::format(
318 "Insufficient data for uint type. Expected {} bits, got {} bits", w,
320 UInt val(data.slice(0, w));
322 return std::any(val);
327 auto structData = std::any_cast<std::map<std::string, std::any>>(obj);
329 if (structData.size() !=
fields.size()) {
330 throw std::runtime_error(std::format(
"struct has {} fields, expected {}",
331 structData.size(),
fields.size()));
334 for (
const auto &[fieldName, fieldType] :
fields) {
335 auto it = structData.find(fieldName);
336 if (it == structData.end())
337 throw std::runtime_error(std::format(
"missing field '{}'", fieldName));
340 fieldType->ensureValid(it->second);
341 }
catch (
const std::runtime_error &e) {
342 throw std::runtime_error(
343 std::format(
"invalid field '{}': {}", fieldName, e.what()));
346 }
catch (
const std::bad_any_cast &) {
347 throw std::runtime_error(
348 std::format(
"must be std::map<std::string, std::any>, but got {}",
355 auto structData = std::any_cast<std::map<std::string, std::any>>(obj);
357 auto handleField = [&](
const std::pair<std::string, const Type *> &f) {
358 const auto &name = f.first;
359 const Type *ty = f.second;
360 auto fieldData = ty->
serialize(structData.at(name));
361 out <<= fieldData.
width();
365 for (
const auto &f :
fields)
368 for (
auto it =
fields.rbegin(); it !=
fields.rend(); ++it)
375 std::map<std::string, std::any> result;
376 auto consumeField = [&](
const std::pair<std::string, const Type *> &f) {
377 const auto &name = f.first;
378 const Type *ty = f.second;
382 for (
auto it =
fields.rbegin(); it !=
fields.rend(); ++it)
385 for (
const auto &f :
fields)
388 return std::any(result);
393 auto arrayData = std::any_cast<std::vector<std::any>>(obj);
395 if (arrayData.size() !=
size) {
396 throw std::runtime_error(std::format(
"array has {} elements, expected {}",
397 arrayData.size(),
size));
400 for (
size_t i = 0; i < arrayData.size(); ++i) {
403 }
catch (
const std::runtime_error &e) {
404 throw std::runtime_error(
405 std::format(
"invalid element {}: {}", i, e.what()));
408 }
catch (
const std::bad_any_cast &) {
409 throw std::runtime_error(std::format(
410 "must be std::vector<std::any>, but got {}", obj.type().name()));
416 auto arrayData = std::any_cast<std::vector<std::any>>(obj);
418 auto handleElem = [&](
const std::any &elem) {
420 out <<= elemData.
width();
424 for (
const auto &e : arrayData)
427 for (
auto it = arrayData.rbegin(); it != arrayData.rend(); ++it)
434 std::vector<std::any> result;
435 result.reserve(
size);
436 for (uint64_t i = 0; i <
size; ++i) {
438 result.push_back(value);
441 std::reverse(result.begin(), result.end());
442 return std::any(result);
447 auto unionData = std::any_cast<std::map<std::string, std::any>>(obj);
449 if (unionData.size() != 1) {
450 throw std::runtime_error(std::format(
451 "union must have exactly 1 active field, got {}", unionData.size()));
454 auto &[activeName, activeValue] = *unionData.begin();
455 for (
const auto &[fieldName, fieldType] :
fields) {
456 if (fieldName == activeName) {
458 fieldType->ensureValid(activeValue);
459 }
catch (
const std::runtime_error &e) {
460 throw std::runtime_error(
461 std::format(
"invalid field '{}': {}", activeName, e.what()));
466 throw std::runtime_error(
467 std::format(
"unknown field '{}' in union", activeName));
468 }
catch (
const std::bad_any_cast &) {
469 throw std::runtime_error(
470 std::format(
"must be std::map<std::string, std::any>, but got {}",
477 auto unionData = std::any_cast<std::map<std::string, std::any>>(obj);
478 auto &[activeName, activeValue] = *unionData.begin();
480 const Type *activeType =
nullptr;
481 for (
const auto &[fieldName, fieldType] :
fields) {
482 if (fieldName == activeName) {
483 activeType = fieldType;
492 if (fieldBits.
width() <
static_cast<uint64_t
>(unionWidth)) {
493 uint64_t padBits = unionWidth - fieldBits.
width();
494 fieldBits <<= padBits;
504 if (data.width() <
static_cast<uint64_t
>(unionWidth))
505 throw std::runtime_error(std::format(
"Insufficient data for union type. "
506 " Expected {} bits, got {} bits",
507 unionWidth, data.width()));
509 BitVector unionBits = data.slice(0, unionWidth);
510 std::map<std::string, std::any> result;
511 for (
const auto &[fieldName, fieldType] :
fields) {
514 std::ptrdiff_t fieldWidth = fieldType->getBitWidth();
515 uint64_t padBits = unionWidth - fieldWidth;
517 fieldData >>= padBits;
518 result[fieldName] = fieldType->deserialize(fieldData);
521 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.
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).
Type aliases provide a named type which forwards to an inner type.
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).
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.
Unions are a tagged collection of fields where only one field is active at a time.
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).
std::ptrdiff_t getBitWidth() const override
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)