[nostalgia] Cleanup and update developer handbook
This commit is contained in:
parent
6074cf7cd6
commit
6160335af3
@ -23,7 +23,7 @@ All components have a platform indicator next to them:
|
|||||||
* Nostalgia
|
* Nostalgia
|
||||||
* core - platform abstraction and user I/O (PG)
|
* core - platform abstraction and user I/O (PG)
|
||||||
* gba - GBA implementation (-G)
|
* gba - GBA implementation (-G)
|
||||||
* sdl - SDL2 implementation (P-)
|
* glfw - GLFW implementation (P-)
|
||||||
* qt - Qt implementation, mostly for studio support (P-)
|
* qt - Qt implementation, mostly for studio support (P-)
|
||||||
* userland - common things needed by all non-bare-metal implementations (P-)
|
* userland - common things needed by all non-bare-metal implementations (P-)
|
||||||
* studio - studio plugin for core (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
|
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
|
in the function, but it will look like it was passed in by value where it is
|
||||||
called and thus not subject to change.
|
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
|
### Error Handling
|
||||||
|
|
||||||
Exceptions are clean and nice and gleefully encouraged in userland code running
|
Exceptions are clean and nice in userland code running in environments with
|
||||||
in environments with expansive system resources, but absolutely unacceptable in
|
expansive system resources, but absolutely unacceptable in code running in
|
||||||
code running in restrictive bare metal environments.
|
restrictive bare metal environments.
|
||||||
The GBA build has them disabled.
|
The GBA build has them disabled.
|
||||||
Exceptions cause the compiler to generate a great deal of extra code that
|
Exceptions cause the compiler to generate a great deal of extra code that
|
||||||
inflates the size of the binary.
|
inflates the size of the binary.
|
||||||
The binary size bloat is often cited as one of the main reasons why many
|
The binary size bloat is often cited as one of the main reasons why many
|
||||||
embedded developers prefer C to C++.
|
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
|
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,
|
a struct that has overloaded operators to behave like an integer error code,
|
||||||
plus some extra fields to enhance debuggability.
|
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:
|
```ox::Result``` can be used as follows:
|
||||||
|
|
||||||
```cpp
|
```cpp
|
||||||
ox::Result<int> foo(int i) {
|
ox::Result<int> foo(int i) noexcept {
|
||||||
if (i < 10) {
|
if (i < 10) {
|
||||||
return i + 1; // implicitly calls ox::Result<T>::Result(T)
|
return i + 1; // implicitly calls ox::Result<T>::Result(T)
|
||||||
}
|
}
|
||||||
@ -222,7 +227,7 @@ void studioCode() {
|
|||||||
doStuff(val);
|
doStuff(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error engineCode() {
|
ox::Error engineCode() noexcept {
|
||||||
auto [val, err] = foo(1);
|
auto [val, err] = foo(1);
|
||||||
oxReturnError(err);
|
oxReturnError(err);
|
||||||
doStuff(val);
|
doStuff(val);
|
||||||
@ -245,7 +250,7 @@ void studioCode() {
|
|||||||
doStuff(valerr.value);
|
doStuff(valerr.value);
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Error engineCode() {
|
ox::Error engineCode() noexcept {
|
||||||
auto valerr = foo(1);
|
auto valerr = foo(1);
|
||||||
oxReturnError(valerr);
|
oxReturnError(valerr);
|
||||||
doStuff(valerr.value);
|
doStuff(valerr.value);
|
||||||
@ -269,11 +274,11 @@ fn f2() -> Result<i32, i32> {
|
|||||||
|
|
||||||
```oxRequire```:
|
```oxRequire```:
|
||||||
```cpp
|
```cpp
|
||||||
ox::Result<int> f() {
|
ox::Result<int> f() noexcept {
|
||||||
// do stuff
|
// do stuff
|
||||||
}
|
}
|
||||||
|
|
||||||
ox::Result<int> f2() {
|
ox::Result<int> f2() noexcept {
|
||||||
oxRequire(i, f()); // const auto [out, oxConcat(oxRequire_err_, __LINE__)] = x; oxReturnError(oxConcat(oxRequire_err_, __LINE__))
|
oxRequire(i, f()); // const auto [out, oxConcat(oxRequire_err_, __LINE__)] = x; oxReturnError(oxConcat(oxRequire_err_, __LINE__))
|
||||||
return i + 4;
|
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 are intended to be quick and temporary insertions.
|
||||||
Debug statements trigger compilation failures if OX_NODEBUG is enabled when CMake is run,
|
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.
|
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
|
This makes ```oxDebug``` preferable to other forms of logging, as temporary prints should
|
||||||
never be checked in anyway.
|
never be checked in.
|
||||||
|
|
||||||
```oxError``` always prints.
|
```oxError``` always prints.
|
||||||
It includes file and line, and is prefixed with a red "ERROR:".
|
It includes file and line, and is prefixed with a red "ERROR:".
|
||||||
@ -381,23 +386,23 @@ struct NostalgiaGraphic {
|
|||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr ox::Error model(T *io, NostalgiaPalette *pal) {
|
constexpr ox::Error model(T *h, NostalgiaPalette *pal) noexcept {
|
||||||
io->template setTypeInfo<NostalgiaPalette>();
|
h->template setTypeInfo<NostalgiaPalette>();
|
||||||
// it is also possible to provide the type name and number of fields as function arguments
|
// it is also possible to provide the type name and number of fields as function arguments
|
||||||
//io->setTypeInfo("net.drinkingtea.nostalgia.core.NostalgiaPalette", 1);
|
//h->setTypeInfo("net.drinkingtea.nostalgia.core.NostalgiaPalette", 1);
|
||||||
oxReturnError(io->field("colors", &pal->colors));
|
oxReturnError(h->field("colors", &pal->colors));
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr ox::Error model(T *io, NostalgiaGraphic *ng) {
|
constexpr ox::Error model(T *h, NostalgiaGraphic *ng) noexcept {
|
||||||
io->template setTypeInfo<NostalgiaGraphic>();
|
h->template setTypeInfo<NostalgiaGraphic>();
|
||||||
oxReturnError(io->field("bpp", &ng->bpp));
|
oxReturnError(h->field("bpp", &ng->bpp));
|
||||||
oxReturnError(io->field("rows", &ng->rows));
|
oxReturnError(h->field("rows", &ng->rows));
|
||||||
oxReturnError(io->field("columns", &ng->columns));
|
oxReturnError(h->field("columns", &ng->columns));
|
||||||
oxReturnError(io->field("defaultPalette", &ng->defaultPalette));
|
oxReturnError(h->field("defaultPalette", &ng->defaultPalette));
|
||||||
oxReturnError(io->field("pal", &ng->pal));
|
oxReturnError(h->field("pal", &ng->pal));
|
||||||
oxReturnError(io->field("pixels", &ng->pixels));
|
oxReturnError(h->field("pixels", &ng->pixels));
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@ -411,7 +416,7 @@ The model system also provides for unions:
|
|||||||
class FileAddress {
|
class FileAddress {
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
friend Error model(T*, FileAddress*);
|
friend constexpr Error model(T*, FileAddress*) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
|
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
|
||||||
@ -425,25 +430,26 @@ class FileAddress {
|
|||||||
uint64_t inode;
|
uint64_t inode;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
protected:
|
||||||
FileAddressType m_type = FileAddressType::None;
|
FileAddressType m_type = FileAddressType::None;
|
||||||
Data m_data;
|
Data m_data;
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error model(T *io, FileAddress::Data *obj) {
|
constexpr Error model(T *h, FileAddress::Data *obj) noexcept {
|
||||||
io->template setTypeInfo<FileAddress::Data>();
|
h->template setTypeInfo<FileAddress::Data>();
|
||||||
oxReturnError(io->field("path", SerStr(&obj->path)));
|
oxReturnError(h->field("path", SerStr(&obj->path)));
|
||||||
oxReturnError(io->field("constPath", SerStr(&obj->path)));
|
oxReturnError(h->field("constPath", SerStr(&obj->path)));
|
||||||
oxReturnError(io->field("inode", &obj->inode));
|
oxReturnError(h->field("inode", &obj->inode));
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
constexpr Error model(T *io, FileAddress *fa) {
|
constexpr Error model(T *h, FileAddress *fa) noexcept {
|
||||||
io->template setTypeInfo<FileAddress>();
|
h->template setTypeInfo<FileAddress>();
|
||||||
oxReturnError(io->field("type", bit_cast<int8_t*>(&fa->m_type)));
|
oxReturnError(h->field("type", bit_cast<int8_t*>(&fa->m_type)));
|
||||||
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
|
||||||
return OxError(0);
|
return OxError(0);
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
Loading…
Reference in New Issue
Block a user