LogCabin
Core/ProtoBuf.cc
Go to the documentation of this file.
00001 /* Copyright (c) 2012 Stanford University
00002  *
00003  * Permission to use, copy, modify, and distribute this software for any
00004  * purpose with or without fee is hereby granted, provided that the above
00005  * copyright notice and this permission notice appear in all copies.
00006  *
00007  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00008  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00009  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00010  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00011  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00012  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00013  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00014  */
00015 
00016 #include <google/protobuf/text_format.h>
00017 #include <memory>
00018 #include <sstream>
00019 
00020 #include "Core/Debug.h"
00021 #include "Core/ProtoBuf.h"
00022 #include "Core/StringUtil.h"
00023 #include "Core/Util.h"
00024 
00025 namespace google {
00026 namespace protobuf {
00027 
00028 bool
00029 operator==(const Message& a, const Message& b)
00030 {
00031     // This is a close enough approximation of equality.
00032     return (a.GetTypeName() == b.GetTypeName() &&
00033             a.DebugString() == b.DebugString());
00034 }
00035 
00036 bool
00037 operator!=(const Message& a, const Message& b)
00038 {
00039     return !(a == b);
00040 }
00041 
00042 bool
00043 operator==(const Message& a, const std::string& bStr)
00044 {
00045     std::unique_ptr<Message> b(a.New());
00046     LogSilencer _;
00047     TextFormat::ParseFromString(bStr, b.get());
00048     return (a == *b);
00049 }
00050 
00051 bool
00052 operator==(const std::string& a, const Message& b)
00053 {
00054     return (b == a);
00055 }
00056 
00057 bool
00058 operator!=(const Message& a, const std::string& b)
00059 {
00060     return !(a == b);
00061 }
00062 
00063 bool
00064 operator!=(const std::string& a, const Message& b)
00065 {
00066     return !(a == b);
00067 }
00068 
00069 } // namespace google::protobuf
00070 } // namespace google
00071 
00072 namespace LogCabin {
00073 namespace Core {
00074 namespace ProtoBuf {
00075 
00076 using Core::StringUtil::replaceAll;
00077 
00078 namespace Internal {
00079 
00080 void
00081 fromString(const std::string& str, google::protobuf::Message& protoBuf)
00082 {
00083     google::protobuf::LogSilencer _;
00084     google::protobuf::TextFormat::ParseFromString(str, &protoBuf);
00085 }
00086 
00087 } // namespace LogCabin::ProtoBuf::Internal
00088 
00089 std::string
00090 dumpString(const google::protobuf::Message& protoBuf,
00091            bool forCopyingIntoTest)
00092 {
00093     std::string output;
00094     google::protobuf::TextFormat::Printer printer;
00095     if (forCopyingIntoTest) {
00096         // Most lines that use these strings will look like this:
00097         // ^    EXPECT_EQ(...,$
00098         // ^              "..."
00099         // ^              "...");
00100         //  12345678901234
00101         // Therefore, we want 14 leading spaces. Tell gtest we want 16, though,
00102         // so that when we add in the surrounding quotes later, lines won't
00103         // wrap.
00104         printer.SetInitialIndentLevel(8);
00105     }
00106     printer.SetUseShortRepeatedPrimitives(true);
00107     printer.PrintToString(protoBuf, &output);
00108     if (forCopyingIntoTest) {
00109         // TextFormat::Printer escapes ' already.
00110         replaceAll(output, "\"", "'");
00111         replaceAll(output, "                ", "              \"");
00112         replaceAll(output, "\n", "\"\n");
00113     }
00114     if (!protoBuf.IsInitialized()) {
00115         std::vector<std::string> errors;
00116         protoBuf.FindInitializationErrors(&errors);
00117         std::ostringstream outputBuf;
00118         outputBuf << output;
00119         for (auto it = errors.begin(); it != errors.end(); ++it) {
00120             if (forCopyingIntoTest) {
00121                  outputBuf << "              \"" << *it << ": UNDEFINED\"\n";
00122             } else {
00123                  outputBuf << *it << ": UNDEFINED\n";
00124             }
00125         }
00126         return output + outputBuf.str();
00127     }
00128     return output;
00129 }
00130 
00131 std::unique_ptr<google::protobuf::Message>
00132 copy(const google::protobuf::Message& protoBuf)
00133 {
00134     std::unique_ptr<google::protobuf::Message> ret(protoBuf.New());
00135     ret->CopyFrom(protoBuf);
00136     return ret;
00137 }
00138 
00139 bool
00140 parse(const Core::Buffer& from,
00141       google::protobuf::Message& to,
00142       uint32_t skipBytes)
00143 {
00144     google::protobuf::LogSilencer logSilencer;
00145     if (!to.ParseFromArray(
00146                         static_cast<const char*>(from.getData()) + skipBytes,
00147                         Util::downCast<int>(from.getLength() - skipBytes))) {
00148         WARNING("Missing fields in protocol buffer of type %s: %s",
00149                 to.GetTypeName().c_str(),
00150                 to.InitializationErrorString().c_str());
00151         return false;
00152     }
00153     return true;
00154 }
00155 
00156 void
00157 serialize(const google::protobuf::Message& from,
00158           Core::Buffer& to,
00159           uint32_t skipBytes)
00160 {
00161     // SerializeToArray seems to always return true, so we explicitly check
00162     // IsInitialized to make sure all required fields are set.
00163     if (!from.IsInitialized()) {
00164         PANIC("Missing fields in protocol buffer of type %s: %s (have %s)",
00165               from.GetTypeName().c_str(),
00166               from.InitializationErrorString().c_str(),
00167               dumpString(from).c_str());
00168     }
00169     uint32_t length = uint32_t(from.ByteSize());
00170     char* data = new char[skipBytes + length];
00171     from.SerializeToArray(data + skipBytes, int(length));
00172     to.setData(data, skipBytes + length, Core::Buffer::deleteArrayFn<char>);
00173 }
00174 
00175 
00176 } // namespace LogCabin::Core::ProtoBuf
00177 } // namespace LogCabin::Core
00178 } // namespace LogCabin
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines