// Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // mcpack2pb - Make protobuf be front-end of mcpack/compack // Author: Ge,Jun (gejun@baidu.com) // Date: Mon Oct 19 17:17:36 CST 2015 #ifndef MCPACK2PB_MCPACK_MCPACK2PB_H #define MCPACK2PB_MCPACK_MCPACK2PB_H #include <google/protobuf/message.h> #include <google/protobuf/io/zero_copy_stream_impl_lite.h> #include "butil/containers/flat_map.h" #include "butil/iobuf.h" #include "mcpack2pb/parser.h" #include "mcpack2pb/serializer.h" namespace mcpack2pb { typedef bool (*SetFieldFn)(::google::protobuf::Message* msg, UnparsedValue& value); // Mapping from filed name to its parsing&setting function. typedef butil::FlatMap<butil::StringPiece, SetFieldFn> FieldMap; enum SerializationFormat { FORMAT_COMPACK, FORMAT_MCPACK_V2 }; struct MessageHandler { // Parse `msg' from `input' as a mcpack_v2 or compack object. // Returns number of bytes consumed. size_t (*parse)(::google::protobuf::Message* msg, ::google::protobuf::io::ZeroCopyInputStream* input); // Parse `msg' from `input' as a mcpack_v2 or compack object removed with header. // Returns true on success. bool (*parse_body)(::google::protobuf::Message* msg, ::google::protobuf::io::ZeroCopyInputStream* input, size_t size); // Serialize `msg' as a mcpack_v2 or compack object into `output'. // The serialization format is decided by `format'. // Returns true on success. bool (*serialize)(const ::google::protobuf::Message& msg, ::google::protobuf::io::ZeroCopyOutputStream* output, SerializationFormat format); // Serialize `msg' as a mcpack_v2 or compack object without header into // `serializer'. The serialization format is decided by `format'. // Returns true on success. void (*serialize_body)(const ::google::protobuf::Message& msg, Serializer& serializer, SerializationFormat format); // ------------------- // Helper functions // ------------------- // Parse `msg' from IOBuf or array which may contain more data than just // the message. // Returns bytes parsed, 0 on error. size_t parse_from_iobuf_prefix(::google::protobuf::Message* msg, const ::butil::IOBuf& buf); size_t parse_from_array_prefix(::google::protobuf::Message* msg, const void* data, int size); // Parse `msg' from IOBuf or array which may just contain the message. // Returns true on success. bool parse_from_iobuf(::google::protobuf::Message* msg, const ::butil::IOBuf& buf); bool parse_from_array(::google::protobuf::Message* msg, const void* data, int size); // Serialize `msg' to IOBuf or string. // Returns true on success. bool serialize_to_iobuf(const ::google::protobuf::Message& msg, ::butil::IOBuf* buf, SerializationFormat format); // TODO(gejun): serialize_to_string is not supported because OutputStream // requires the embedded zero-copy stream to return permanent memory blocks // to support reserve() however the string inside StringOutputStream may // be resized and invalidates previous returned memory blocks. }; static const MessageHandler INVALID_MESSAGE_HANDLER = {NULL, NULL, NULL, NULL}; // if the *.pb.cc and *.pb.h was generated by mcpack2pb. This function will be // called with the mcpack/compack parser and serializer BEFORE main(). void register_message_handler_or_die(const std::string& full_name, const MessageHandler& handler); // Find the registered parser/serializer by `full_name' // e.g. "example.SampleMessage". // If the handler was not registered, function pointers inside are NULL. MessageHandler find_message_handler(const std::string& full_name); // inline impl. inline size_t MessageHandler::parse_from_iobuf_prefix( ::google::protobuf::Message* msg, const ::butil::IOBuf& buf) { if (parse == NULL) { LOG(ERROR) << "`parse' is NULL"; return 0; } ::butil::IOBufAsZeroCopyInputStream zc_stream(buf); return parse(msg, &zc_stream); } inline bool MessageHandler::parse_from_iobuf( ::google::protobuf::Message* msg, const ::butil::IOBuf& buf) { if (parse == NULL) { LOG(ERROR) << "`parse' is NULL"; return 0; } ::butil::IOBufAsZeroCopyInputStream zc_stream(buf); return parse(msg, &zc_stream) == buf.size(); } inline size_t MessageHandler::parse_from_array_prefix( ::google::protobuf::Message* msg, const void* data, int size) { if (parse == NULL) { LOG(ERROR) << "`parse' is NULL"; return 0; } ::google::protobuf::io::ArrayInputStream zc_stream(data, size); return parse(msg, &zc_stream); } inline bool MessageHandler::parse_from_array( ::google::protobuf::Message* msg, const void* data, int size) { if (parse == NULL) { LOG(ERROR) << "`parse' is NULL"; return 0; } ::google::protobuf::io::ArrayInputStream zc_stream(data, size); return (int)parse(msg, &zc_stream) == size; } inline bool MessageHandler::serialize_to_iobuf( const ::google::protobuf::Message& msg, ::butil::IOBuf* buf, SerializationFormat format) { if (serialize == NULL) { LOG(ERROR) << "`serialize' is NULL"; return false; } ::butil::IOBufAsZeroCopyOutputStream zc_stream(buf); return serialize(msg, &zc_stream, format); } } // namespace mcpack2pb #endif // MCPACK2PB_MCPACK_MCPACK2PB_H