29#ifndef EASYPC_ARCHIVE_H
30#define EASYPC_ARCHIVE_H
36#include <initializer_list>
61 template <
typename... ARGS>
64 (
find( aArgs ), ... );
69 return LOAD_TASK( std::coroutine_handle<promise_type>::from_promise( *
this ) );
88 using HANDLE = std::coroutine_handle<promise_type>;
91 m_handle( std::exchange( aOther.m_handle, {} ) )
106 void await_suspend( std::coroutine_handle<> aAwaiting );
136using REGISTRY = std::map<std::string, std::function<std::unique_ptr<OBJECT>()>, std::less<>>;
143 for(
const char*
name : aNames )
144 aReg[
name] = []() -> std::unique_ptr<OBJECT>
146 return std::make_unique<T>();
187 ARCHIVE(
const uint8_t* aData,
size_t aSize,
DOC_KIND aKind, int32_t aProduct );
195 int32_t
I32() {
return static_cast<int32_t
>(
U32() ); }
201 void Skip(
size_t aLen );
204 void Require(
size_t aLen )
const;
227 template <
typename T>
244 template <
typename T>
283 static std::unique_ptr<OBJECT>
Create(
const char* aClass );
382 consteval FIELD_ROW(
int aSince,
int aUntil,
const char* aOps ) :
387 for(
const char* p = aOps; *p; ++p )
389 if( std::string_view(
"b1ifsoa 0123456789" ).
find( *p ) == std::string_view::npos )
390 throw "unknown SkipFields op";
405template <
typename BASE>
410 co_await BASE::Load( aAr );
411 co_await SkipRows( aAr, this->ItemFormat( aAr ),
Rows );
414 std::span<const FIELD_ROW>
Rows;
418template <
typename BASE>
421 aReg[aName] = [aRows]() -> std::unique_ptr<OBJECT>
423 std::unique_ptr<SKIPPED<BASE>> obj = std::make_unique<SKIPPED<BASE>>();
An embedded member for a loader to co_await: no tag and no load-array slot.
void await_resume() const noexcept
void await_suspend(std::coroutine_handle<> aAwaiting)
EMBEDDED_AWAITER(ARCHIVE &aArchive, OBJECT &aObject)
The next object tag for a loader to co_await: null, a back reference, or a new object fully loaded.
void await_suspend(std::coroutine_handle<> aAwaiting)
OBJECT_AWAITER(ARCHIVE &aArchive)
OBJECT * await_resume() const
Object that must be a T or null.
OBJECT_AWAITER(ARCHIVE &aArchive)
One archive load stream; it owns every object it creates.
size_t & ParentWalkDepth() const
Bounds ItemFormat parent walks, which recurse through file-supplied parent tags.
void pushTask(LOAD_TASK::HANDLE aHandle)
int CurrentReadFormat() const
OBJECT * readTag(bool &aIsNew)
Read a tag; a new object is created and mapped but not loaded (aIsNew)
void SetShapeFormat(int aFormat)
void MapObject(OBJECT *aObject)
A load-array slot for an object not read through a tag.
EMBEDDED_AWAITER Embedded(OBJECT &aObject, const char *aClass)
static std::unique_ptr< OBJECT > Create(const char *aClass)
An object of a registered class, not yet loaded.
void drive(LOAD_TASK aRoot)
Run aRoot and everything it awaits until it finishes, rethrowing its failure.
void Require(size_t aLen) const
Throw unless aLen more bytes remain.
wxString ReadString()
ANSI (windows-1252) or the 0xFF 0xFFFE UTF-16 form.
void pushObjectLoad(OBJECT &aObject, uint16_t aSchema)
std::vector< std::unique_ptr< OBJECT > > TakeObjects()
uint32_t stringLength(bool &aUnicode)
The string length prefix; aUnicode for the UTF-16 form.
void SetProduct(int32_t aProduct)
TYPED_AWAITER< T > ObjectAs()
static constexpr int MAX_DEPTH
void SetReadFormat(int aFormat)
uint16_t ObjectSchema() const
std::vector< std::unique_ptr< OBJECT > > m_objects
void throwBadClass(const OBJECT &aObject) const
bool InBool()
one or four bytes, depending on the active format
int DocumentVersion() const
void SetDocumentVersion(int aVersion)
int OrphanFormat() const
A null parent tag is the document: the header version in a design, else the current read format.
std::vector< SLOT > m_load
slot 0 is the null slot
void SetBooleanIsByte(bool aByte)
std::vector< FRAME > m_frames
OBJECT * ReadObject()
ReadObject and LoadEmbedded outside any loader, running the nested loads to completion.
uint32_t Count()
a 16-bit count, 0xFFFF escaping to 32 bits
void LoadEmbedded(OBJECT &aObject, const char *aClass)
size_t LoadArraySize() const
ARCHIVE(const uint8_t *aData, size_t aSize, DOC_KIND aKind, int32_t aProduct)
aData must outlive the archive; aProduct is the product key in force
A loader coroutine. Awaiting one queues it on its archive's frame stack instead of nesting the call.
LOAD_TASK & operator=(LOAD_TASK &&)=delete
bool await_ready() const noexcept
void await_resume() const noexcept
LOAD_TASK(LOAD_TASK &&aOther) noexcept
std::coroutine_handle< promise_type > HANDLE
LOAD_TASK(HANDLE aHandle)
std::map< std::string, std::function< std::unique_ptr< OBJECT >()>, std::less<> > REGISTRY
LOAD_TASK SkipRows(ARCHIVE &aAr, int aVersion, std::span< const FIELD_ROW > aRows)
SkipFields for every row aVersion falls in, in order.
void RegisterGeometryClasses(REGISTRY &aReg)
void RegisterLibraryClasses(REGISTRY &aReg)
LOAD_TASK SkipFields(ARCHIVE &aAr, std::string_view aOps)
Read and drop a run of fields described by aOps, each letter optionally followed by a repeat count: b...
PRODUCT_KEY
Product keys, the design header's or the library LibFormat's.
@ PRODUCT_DESIGNSPARK_CREATOR
@ PRODUCT_DESIGNSPARK_PRO
DOC_KIND
Document kind, from the FileType stream or the file extension for projects.
@ SCH_SYMBOL
one item stream of a Schematic Symbol Library
@ COMPONENT
one stream of a Component Library storage
@ PCB_SYMBOL
one item stream of a PCB Symbol Library
void RegisterRootClasses(REGISTRY &aReg)
void RegisterSkipped(REGISTRY &aReg, const char *aName, std::span< const FIELD_ROW > aRows)
void Register(REGISTRY &aReg, std::initializer_list< const char * > aNames)
Register the class names whose objects load as a T.
void RegisterStyleClasses(REGISTRY &aReg)
void RegisterConnectivityClasses(REGISTRY &aReg)
OBJECT * Object
whose Load this is, named in a failure
bool ObjectLoad
counts towards MAX_DEPTH
const char * ClassName
set for a class slot
consteval FIELD_ROW(int aSince, int aUntil, const char *aOps)
Rejects an unknown op at compile time, since a misread op would misalign every later field.
void find(ARCHIVE &aArchive)
std::exception_ptr m_error
void return_void() noexcept
void unhandled_exception() noexcept
promise_type(ARGS &... aArgs)
std::suspend_always initial_suspend() noexcept
std::suspend_always final_suspend() noexcept
LOAD_TASK get_return_object()
Root of every deserialized object.
virtual LOAD_TASK Load(ARCHIVE &aAr)
Read this object's fields.
size_t Offset
stream offset of the tag or of an embedded member's first field
virtual ~OBJECT()=default
uint16_t Schema
object schema from the class tag, 0 for an embedded member
const char * ClassName
registered class name
virtual int ItemFormat(const ARCHIVE &aAr) const
The version this object gates on; the base is the archive's current read format.
A class no importer reads: its base's fields, then a field program on its format.
LOAD_TASK Load(ARCHIVE &aAr) override
std::span< const FIELD_ROW > Rows