[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    [dferry] /: Help reduce boilerplate when copying from Reader to Writer.
From:       Andreas Hartmetz <ahartmetz () gmail ! com>
Date:       2016-11-17 1:34:24
Message-ID: E1c7Baq-0002rY-Sl () code ! kde ! org
[Download RAW message or body]

Git commit 73cef05cdc1655cb0d1e0f6cbe8873d5548c82c7 by Andreas Hartmetz.
Committed on 17/11/2016 at 00:46.
Pushed by ahartmetz into branch 'master'.

Help reduce boilerplate when copying from Reader to Writer.

This is not only useful in the tests.

M  +107  -0    serialization/arguments.cpp
M  +5    -0    serialization/arguments.h
M  +14   -46   tests/serialization/tst_arguments.cpp

http://commits.kde.org/dferry/73cef05cdc1655cb0d1e0f6cbe8873d5548c82c7

diff --git a/serialization/arguments.cpp b/serialization/arguments.cpp
index 731f23b..3d61e3d 100644
--- a/serialization/arguments.cpp
+++ b/serialization/arguments.cpp
@@ -51,6 +51,113 @@ static byte alignmentLog2(uint32 alignment)
     return alignLog[alignment];
 }
 
+// When using this to iterate over the reader, it will make an exact copy using the Writer.
+// You need to do something only in states where something special should happen.
+// To check errors, "simply" (sorry!) check the reader->state() and writer()->state().
+// Note that you don't have to check the state before each element, it is fine to call
+// read / write functions in error state, including with garbage data from the possibly
+// invalid reader, and the reader / writer state will remain frozen in the state in which
+// the first error occurred
+// TODO: that text above belongs into a "Reader and Writer state / errors" explanation of the docs
+
+// static
+void Arguments::copyOneElement(Arguments::Reader *reader, Arguments::Writer *writer)
+{
+    switch(reader->state()) {
+    case Arguments::BeginStruct:
+        reader->beginStruct();
+        writer->beginStruct();
+        break;
+    case Arguments::EndStruct:
+        reader->endStruct();
+        writer->endStruct();
+        break;
+    case Arguments::BeginVariant:
+        reader->beginVariant();
+        writer->beginVariant();
+        break;
+    case Arguments::EndVariant:
+        reader->endVariant();
+        writer->endVariant();
+        break;
+    case Arguments::BeginArray: {
+        // Application note: to avoid handling arrays as primitive (where applicable), just don't
+        // call this function in BeginArray state and do as in the else case.
+        const Arguments::IoState primitiveType = reader->peekPrimitiveArray();
+        if (primitiveType != BeginArray) { // InvalidData can't happen because the state *is* BeginArray
+            const std::pair<Arguments::IoState, chunk> arrayData = reader->readPrimitiveArray();
+            writer->writePrimitiveArray(arrayData.first, arrayData.second);
+        } else {
+            const bool hasData = reader->beginArray(Arguments::Reader::ReadTypesOnlyIfEmpty);
+            writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray
+                                       : Arguments::Writer::WriteTypesOfEmptyArray);
+        }
+        break; }
+    case Arguments::EndArray:
+        reader->endArray();
+        writer->endArray();
+        break;
+    case Arguments::BeginDict: {
+        const bool hasData = reader->beginDict(Arguments::Reader::ReadTypesOnlyIfEmpty);
+        writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray
+                                    : Arguments::Writer::WriteTypesOfEmptyArray);
+        break; }
+    case Arguments::EndDict:
+        reader->endDict();
+        writer->endDict();
+        break;
+    case Arguments::Byte:
+        writer->writeByte(reader->readByte());
+        break;
+    case Arguments::Boolean:
+        writer->writeBoolean(reader->readBoolean());
+        break;
+    case Arguments::Int16:
+        writer->writeInt16(reader->readInt16());
+        break;
+    case Arguments::Uint16:
+        writer->writeUint16(reader->readUint16());
+        break;
+    case Arguments::Int32:
+        writer->writeInt32(reader->readInt32());
+        break;
+    case Arguments::Uint32:
+        writer->writeUint32(reader->readUint32());
+        break;
+    case Arguments::Int64:
+        writer->writeInt64(reader->readInt64());
+        break;
+    case Arguments::Uint64:
+        writer->writeUint64(reader->readUint64());
+        break;
+    case Arguments::Double:
+        writer->writeDouble(reader->readDouble());
+        break;
+    case Arguments::String: {
+        const cstring s = reader->readString();
+        writer->writeString(s);
+        break; }
+    case Arguments::ObjectPath: {
+        const cstring objectPath = reader->readObjectPath();
+        writer->writeObjectPath(objectPath);
+        break; }
+    case Arguments::Signature: {
+        const cstring signature = reader->readSignature();
+        writer->writeSignature(signature);
+        break; }
+    case Arguments::UnixFd:
+        writer->writeUnixFd(reader->readUnixFd());
+        break;
+    // special cases follow
+    case Arguments::Finished:
+        break; // You *probably* want to handle that one in the caller, but you don't have to
+    case Arguments::NeedMoreData:
+        break; // No way to handle that one here
+    default:
+        break; // dito
+    }
+}
+
 // helper to verify the max nesting requirements of the d-bus spec
 struct Nesting
 {
diff --git a/serialization/arguments.h b/serialization/arguments.h
index 5d86866..781baed 100644
--- a/serialization/arguments.h
+++ b/serialization/arguments.h
@@ -37,6 +37,9 @@ class Message;
 class DFERRY_EXPORT Arguments
 {
 public:
+    class Reader;
+    class Writer;
+
     enum SignatureType
     {
         MethodSignature = 0,
@@ -126,6 +129,8 @@ public:
     static bool isObjectPathElementValid(cstring pathElement);
     static bool isSignatureValid(cstring signature, SignatureType type = MethodSignature);
 
+    static void copyOneElement(Reader *reader, Writer *writer);
+
 private:
     struct podCstring // Same as cstring but without ctor.
                       // Can't put the cstring type into a union because it has a constructor :/
diff --git a/tests/serialization/tst_arguments.cpp b/tests/serialization/tst_arguments.cpp
index c8a04fd..d2dabf9 100644
--- a/tests/serialization/tst_arguments.cpp
+++ b/tests/serialization/tst_arguments.cpp
@@ -288,66 +288,34 @@ static void defaultReadToWrite(Arguments::Reader *reader, Arguments::Writer *wri
 {
     switch(reader->state()) {
     case Arguments::BeginStruct:
-        reader->beginStruct();
-        writer->beginStruct();
-        break;
     case Arguments::EndStruct:
-        reader->endStruct();
-        writer->endStruct();
-        break;
     case Arguments::BeginVariant:
-        reader->beginVariant();
-        writer->beginVariant();
-        break;
     case Arguments::EndVariant:
-        reader->endVariant();
-        writer->endVariant();
-        break;
-    case Arguments::BeginArray: {
-        const bool hasData = reader->beginArray(Arguments::Reader::ReadTypesOnlyIfEmpty);
-        writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray
-                                    : Arguments::Writer::WriteTypesOfEmptyArray);
-        break; }
     case Arguments::EndArray:
-        reader->endArray();
-        writer->endArray();
-        break;
-    case Arguments::BeginDict: {
-        const bool hasData = reader->beginDict(Arguments::Reader::ReadTypesOnlyIfEmpty);
-        writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray
-                                    : Arguments::Writer::WriteTypesOfEmptyArray);
-        break; }
     case Arguments::EndDict:
-        reader->endDict();
-        writer->endDict();
-        break;
     case Arguments::Byte:
-        writer->writeByte(reader->readByte());
-        break;
     case Arguments::Boolean:
-        writer->writeBoolean(reader->readBoolean());
-        break;
     case Arguments::Int16:
-        writer->writeInt16(reader->readInt16());
-        break;
     case Arguments::Uint16:
-        writer->writeUint16(reader->readUint16());
-        break;
     case Arguments::Int32:
-        writer->writeInt32(reader->readInt32());
-        break;
     case Arguments::Uint32:
-        writer->writeUint32(reader->readUint32());
-        break;
     case Arguments::Int64:
-        writer->writeInt64(reader->readInt64());
-        break;
     case Arguments::Uint64:
-        writer->writeUint64(reader->readUint64());
-        break;
     case Arguments::Double:
-        writer->writeDouble(reader->readDouble());
+    case Arguments::UnixFd:
+        Arguments::copyOneElement(reader, writer);
         break;
+    // special handling for BeginArray and BeginDict to avoid "fast copy" for primitive arrays
+    case Arguments::BeginArray: {
+        const bool hasData = reader->beginArray(Arguments::Reader::ReadTypesOnlyIfEmpty);
+        writer->beginArray(hasData ? Arguments::Writer::NonEmptyArray
+                                    : Arguments::Writer::WriteTypesOfEmptyArray);
+        break; }
+    case Arguments::BeginDict: {
+        const bool hasData = reader->beginDict(Arguments::Reader::ReadTypesOnlyIfEmpty);
+        writer->beginDict(hasData ? Arguments::Writer::NonEmptyArray
+                                    : Arguments::Writer::WriteTypesOfEmptyArray);
+        break; }
     case Arguments::String: {
         const cstring s = reader->readString();
         if (!reader->isInsideEmptyArray()) {
@@ -369,7 +337,7 @@ static void defaultReadToWrite(Arguments::Reader *reader, Arguments::Writer *wri
         }
         writer->writeSignature(signature);
         break; }
-    case Arguments::UnixFd:
+
         writer->writeUnixFd(reader->readUnixFd());
         break;
     // special cases follow
[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic