Commit 3e3d0398 authored by EXT Arnaud Clère's avatar EXT Arnaud Clère

Added external QBind example and IBind explanation to README

parent 98d41ca5
......@@ -74,6 +74,8 @@ for data formats supporting it like [CBOR value sharing tags](http://cbor.schmor
## Examples
### Extending QBind to C++ types
One can rely on Qt reflection to bind a Q_OBJECT or Q_GADGET stored properties using `QBIND_GADGET_WITH_METAOBJECT` macro
```cpp
class Phone {
......@@ -242,7 +244,29 @@ if (/*... &&*/
</details>
It is also possible to define missing QBind specializations for any C++ type using external QBind class specializations.
Each specialization must implement at least the bind() method for lvalue references. It may also overload bind() for rvalue
references to support temporaries, and for const lvalue reference to efficiently support copyable types.
```cpp
template<> struct QBind<QColor> {
static Cursor bind(Val<Cursor>&& v, QColor&& c) { QColor copy(c); return bind(std::move(v),copy); } // supports writing temporaries and const QColor&
static Cursor bind(Val<Cursor>&& v, QColor& c) {
if (!c.isValid()) {
return v.null();
}
Rec<Cursor> r = v.record();
switch(c.spec()) {
case QColor::Spec::Rgb : r = r.sequence("RGB" ).bind(c.red ()).bind(c.green ()).bind(c.blue ()); break;
case QColor::Spec::Hsl : r = r.sequence("HSL" ).bind(c.hslHue()).bind(c.hslSaturation()).bind(c.lightness()); break;
//...
}
if (c.alpha()<255) { r = r.bind("alpha",quint8(c.alpha())); }
return r.bind("base", 255);
}
};
```
### Extending QBind to custom formats
Defining a custom format for, say, console output only requires implementing a few `IWriter` abstract methods:
```cpp
......@@ -250,10 +274,10 @@ class MyTextWriter : public IWriter
{
//...
protected:
bool _sequence(quint32* =nullptr) { ba->append("["); return true; }
bool _record (quint32* =nullptr) { ba->append("["); return true; }
bool _null ( ) { return true; }
bool _bind ( const char* u8) { ba->append( u8); return true; }
bool _sequence(quint32* =nullptr) { ba->append("[") ; return true; }
bool _record (quint32* =nullptr) { ba->append("[") ; return true; }
bool _null ( ) { return true; }
bool _bind ( const char* u8) { ba->append( u8) ; return true; }
bool _item (QIdentifierLiteral n) { ba->append(" ").append(n).append(":"); return true; }
bool _item ( ) { ba->append(" ") ; return true; }
......@@ -270,6 +294,11 @@ MyTextWriter(&ba) << 1.333333333333f << PI << ascii << false << color ;
// [ 1.33333 3.14159 ascii characters are common in QDebug false [ RGB:[ 45 0 186] base:255]
```
Implementing a custom reader requires implementing a few `IReader` methods. This is always more complex because reading
needs to perform much more checks and may have to report transient errors instead of returning `true` as `MyTextWriter` does.
Both `IWriter` and `IReader` are convenient base classes which implement most of `IBind` interface used by QBind<T> with
generic text representations of boolean, numbers, etc.
Since QBind supports Val<_> on the right-hand side, translating between generic data formats or structures is a one-liner:
```cpp
// baIn = {"names":["John","Doe"],"height":1.7500000000000002,"age":-1,"phones":["+44 1234567","+44 2345678"],"comments":"","children":[]}
......@@ -388,6 +417,12 @@ Phone(Phone::Home, "+44 1234567")
bf647479706502666e756d6265726b2b34342031323334353637ff
```
> WARNING: The QBind ability to adequately bind C++ types and formats is only limited by the set of natively supported C++ types and
> the support of meta() by each format. `IBind` natively supports QDataStream::operator<<() types and could be extended to include
> native types which can have efficient binary representations like QUuid. Alternatively, the fluent interface currently contains an
> optional TImpl parameter that could be used to define another set of natively supported C++ types, or removed to simplify the fluent
> interface.
### Write performance
Overall, QBind demonstrates write performance superior to existing Qt classes except QDataStream (which does not meet our W1
......
......@@ -172,9 +172,9 @@ struct QBind<QColor> {
} while (!n.isNull());
Rec<Cursor> r = v.record();
switch(c.spec()) {
case QColor::Spec::Rgb : r = r.sequence("RGB" ).bind(quint8(c.red ())).bind(quint8(c.green ())).bind(quint8(c.blue ())) .out(); break;
case QColor::Spec::Hsl : r = r.sequence("HSL" ).bind(qint16(c.hslHue())).bind(quint8(c.hslSaturation())).bind(quint8(c.lightness())) .out(); break;
case QColor::Spec::Hsv : r = r.sequence("HSV" ).bind(qint16(c.hsvHue())).bind(quint8(c.hsvSaturation())).bind(quint8(c.value ())) .out(); break;
case QColor::Spec::Rgb : r = r.sequence("RGB" ).bind(quint8(c.red ())).bind(quint8(c.green ())).bind(quint8(c.blue ())) .out(); break;
case QColor::Spec::Hsl : r = r.sequence("HSL" ).bind(qint16(c.hslHue())).bind(quint8(c.hslSaturation())).bind(quint8(c.lightness())) .out(); break;
case QColor::Spec::Hsv : r = r.sequence("HSV" ).bind(qint16(c.hsvHue())).bind(quint8(c.hsvSaturation())).bind(quint8(c.value ())) .out(); break;
case QColor::Spec::Cmyk: r = r.sequence("CMYK").bind(quint8(c.cyan ())).bind(quint8(c.magenta ())).bind(quint8(c.yellow ())).bind(quint8(c.black())).out(); break;
default: Q_ASSERT(false);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment