LogCabin
|
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