diff --git a/developer-handbook.md b/developer-handbook.md index dc852fd0..3d315f2a 100644 --- a/developer-handbook.md +++ b/developer-handbook.md @@ -23,7 +23,7 @@ All components have a platform indicator next to them: * Nostalgia * core - platform abstraction and user I/O (PG) * gba - GBA implementation (-G) - * sdl - SDL2 implementation (P-) + * glfw - GLFW implementation (P-) * qt - Qt implementation, mostly for studio support (P-) * userland - common things needed by all non-bare-metal implementations (P-) * studio - studio plugin for core (P-) @@ -134,20 +134,25 @@ As parameters, references should always be const. A non-const reference is generally used because the parameter value is changed in the function, but it will look like it was passed in by value where it is called and thus not subject to change. -The reference operator makes it clear that the value can and likely will change. +The reference operator makes it clear to the caller that the value can and +likely will change. + +## Project Systems ### Error Handling -Exceptions are clean and nice and gleefully encouraged in userland code running -in environments with expansive system resources, but absolutely unacceptable in -code running in restrictive bare metal environments. +Exceptions are clean and nice in userland code running in environments with +expansive system resources, but absolutely unacceptable in code running in +restrictive bare metal environments. The GBA build has them disabled. Exceptions cause the compiler to generate a great deal of extra code that inflates the size of the binary. The binary size bloat is often cited as one of the main reasons why many embedded developers prefer C to C++. -Instead of throwing exceptions, all engine code must return error codes. +Instead of throwing exceptions, all engine code must return Ox error codes. +For the sake of consistency, try to stick to Ox error codes in non-engine code +as well. Nostalgia and Ox both use ```ox::Error``` to report errors. ```ox::Error``` is a struct that has overloaded operators to behave like an integer error code, plus some extra fields to enhance debuggability. @@ -168,7 +173,7 @@ declared as ```noexcept``` and all exceptions should be translated to an ```ox::Result``` can be used as follows: ```cpp -ox::Result foo(int i) { +ox::Result foo(int i) noexcept { if (i < 10) { return i + 1; // implicitly calls ox::Result::Result(T) } @@ -222,7 +227,7 @@ void studioCode() { doStuff(val); } -ox::Error engineCode() { +ox::Error engineCode() noexcept { auto [val, err] = foo(1); oxReturnError(err); doStuff(val); @@ -245,7 +250,7 @@ void studioCode() { doStuff(valerr.value); } -ox::Error engineCode() { +ox::Error engineCode() noexcept { auto valerr = foo(1); oxReturnError(valerr); doStuff(valerr.value); @@ -269,11 +274,11 @@ fn f2() -> Result { ```oxRequire```: ```cpp -ox::Result f() { +ox::Result f() noexcept { // do stuff } -ox::Result f2() { +ox::Result f2() noexcept { oxRequire(i, f()); // const auto [out, oxConcat(oxRequire_err_, __LINE__)] = x; oxReturnError(oxConcat(oxRequire_err_, __LINE__)) return i + 4; } @@ -302,8 +307,8 @@ Where trace statements are intended to be written with thoughtfulness, debug statements are intended to be quick and temporary insertions. Debug statements trigger compilation failures if OX_NODEBUG is enabled when CMake is run, as it is on Jenkins builds, so ```oxDebug``` statements should never be checked in. -This makes oxDebug preferable to other forms of logging, as temporary prints should -never be checked in anyway. +This makes ```oxDebug``` preferable to other forms of logging, as temporary prints should +never be checked in. ```oxError``` always prints. It includes file and line, and is prefixed with a red "ERROR:". @@ -381,23 +386,23 @@ struct NostalgiaGraphic { }; template -constexpr ox::Error model(T *io, NostalgiaPalette *pal) { - io->template setTypeInfo(); +constexpr ox::Error model(T *h, NostalgiaPalette *pal) noexcept { + h->template setTypeInfo(); // it is also possible to provide the type name and number of fields as function arguments - //io->setTypeInfo("net.drinkingtea.nostalgia.core.NostalgiaPalette", 1); - oxReturnError(io->field("colors", &pal->colors)); + //h->setTypeInfo("net.drinkingtea.nostalgia.core.NostalgiaPalette", 1); + oxReturnError(h->field("colors", &pal->colors)); return OxError(0); } template -constexpr ox::Error model(T *io, NostalgiaGraphic *ng) { - io->template setTypeInfo(); - oxReturnError(io->field("bpp", &ng->bpp)); - oxReturnError(io->field("rows", &ng->rows)); - oxReturnError(io->field("columns", &ng->columns)); - oxReturnError(io->field("defaultPalette", &ng->defaultPalette)); - oxReturnError(io->field("pal", &ng->pal)); - oxReturnError(io->field("pixels", &ng->pixels)); +constexpr ox::Error model(T *h, NostalgiaGraphic *ng) noexcept { + h->template setTypeInfo(); + oxReturnError(h->field("bpp", &ng->bpp)); + oxReturnError(h->field("rows", &ng->rows)); + oxReturnError(h->field("columns", &ng->columns)); + oxReturnError(h->field("defaultPalette", &ng->defaultPalette)); + oxReturnError(h->field("pal", &ng->pal)); + oxReturnError(h->field("pixels", &ng->pixels)); return OxError(0); } ``` @@ -411,7 +416,7 @@ The model system also provides for unions: class FileAddress { template - friend Error model(T*, FileAddress*); + friend constexpr Error model(T*, FileAddress*) noexcept; public: static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress"; @@ -425,25 +430,26 @@ class FileAddress { uint64_t inode; }; + protected: FileAddressType m_type = FileAddressType::None; Data m_data; }; template -constexpr Error model(T *io, FileAddress::Data *obj) { - io->template setTypeInfo(); - oxReturnError(io->field("path", SerStr(&obj->path))); - oxReturnError(io->field("constPath", SerStr(&obj->path))); - oxReturnError(io->field("inode", &obj->inode)); +constexpr Error model(T *h, FileAddress::Data *obj) noexcept { + h->template setTypeInfo(); + oxReturnError(h->field("path", SerStr(&obj->path))); + oxReturnError(h->field("constPath", SerStr(&obj->path))); + oxReturnError(h->field("inode", &obj->inode)); return OxError(0); } template -constexpr Error model(T *io, FileAddress *fa) { - io->template setTypeInfo(); - oxReturnError(io->field("type", bit_cast(&fa->m_type))); - oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast(fa->m_type)))); +constexpr Error model(T *h, FileAddress *fa) noexcept { + h->template setTypeInfo(); + oxReturnError(h->field("type", bit_cast(&fa->m_type))); + oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast(fa->m_type)))); return OxError(0); } ```