[struct_pb]Refact struct pb (#680)
This commit is contained in:
parent
350fbc4352
commit
476b5842d4
|
|
@ -30,7 +30,7 @@ jobs:
|
|||
CXX=g++ CC=gcc
|
||||
cmake -B ${{github.workspace}}/build \
|
||||
-DCMAKE_BUILD_TYPE=Debug \
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF -DBUILD_EXAMPLES=OFF -DBUILD_BENCHMARK=OFF
|
||||
cmake --build ${{github.workspace}}/build -j
|
||||
cd ${{github.workspace}}/build/output/tests
|
||||
./struct_pack_test
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ jobs:
|
|||
cmake -B ${{github.workspace}}/build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \
|
||||
-DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}}
|
||||
|
||||
|
|
@ -146,7 +146,7 @@ jobs:
|
|||
-DBUILD_WITH_LIBCXX=${{matrix.libcxx}} \
|
||||
-DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \
|
||||
-DUSE_CCACHE=${{env.ccache}} -DCMAKE_C_COMPILER=clang-17 -DCMAKE_CXX_COMPILER=clang++-17\
|
||||
-DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
-DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}}
|
||||
|
|
|
|||
|
|
@ -80,7 +80,7 @@ jobs:
|
|||
cmake -B ${{github.workspace}}/build -G Ninja \
|
||||
-DCMAKE_BUILD_TYPE=${{matrix.mode}} -DBUILD_WITH_LIBCXX=${{matrix.libcxx}} -DYLT_ENABLE_SSL=${{matrix.ssl}} \
|
||||
-DUSE_CCACHE=${{env.ccache}} \
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
-DBUILD_CORO_HTTP=OFF -DBUILD_CORO_IO=OFF -DBUILD_STRUCT_PB=ON -DBUILD_CORO_RPC=OFF -DBUILD_EASYLOG=OFF -DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}}
|
||||
|
|
@ -118,7 +118,7 @@ jobs:
|
|||
-DCMAKE_BUILD_TYPE=${{matrix.mode}} \
|
||||
-DYLT_ENABLE_IO_URING=${{matrix.io_uring}} \
|
||||
-DUSE_CCACHE=${{env.ccache}} \
|
||||
-DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_PB=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
-DBUILD_STRUCT_JSON=OFF -DBUILD_STRUCT_XML=OFF -DBUILD_STRUCT_PACK=OFF -DBUILD_STRUCT_YAML=OFF -DBUILD_UTIL=OFF
|
||||
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}/build --config ${{matrix.mode}}
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ jobs:
|
|||
with:
|
||||
key: ${{ github.job }}-${{ matrix.mode}}-arch-${{ matrix.arch}}
|
||||
- name: Configure CMake
|
||||
run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF
|
||||
run: cmake -B ${{github.workspace}}\build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.mode }} -DYLT_ENABLE_SSL=${{matrix.ssl}} -DBUILD_STRUCT_PB=OFF -DUSE_CCACHE=ON -DENABLE_CPP_20=OFF
|
||||
- name: Build
|
||||
run: cmake --build ${{github.workspace}}\build
|
||||
- name: Test
|
||||
|
|
|
|||
|
|
@ -22,7 +22,6 @@ if(CMAKE_PROJECT_NAME STREQUAL "yaLanTingLibs") # if ylt is top-level project
|
|||
include_directories(src/include)
|
||||
|
||||
include(cmake/utils.cmake)
|
||||
include(cmake/struct_pb.cmake)
|
||||
include(cmake/build.cmake)
|
||||
include(cmake/develop.cmake)
|
||||
# add project config, such as enable_ssl.
|
||||
|
|
|
|||
|
|
@ -504,11 +504,9 @@ No dependency.
|
|||
|
||||
No dependency.
|
||||
|
||||
### struct_pb (optional)
|
||||
### struct_pb
|
||||
|
||||
In default, struct_pb wont be installed. You need install protobuf manually.
|
||||
|
||||
- [protobuf](https://protobuf.dev/)
|
||||
No dependency.
|
||||
|
||||
|
||||
## Standalone sublibraries
|
||||
|
|
|
|||
|
|
@ -1,224 +0,0 @@
|
|||
function(protobuf_generate_modified)
|
||||
find_package(Protobuf REQUIRED)
|
||||
set(_options APPEND_PATH DESCRIPTORS)
|
||||
set(_singleargs LANGUAGE OUT_VAR EXPORT_MACRO PROTOC_OUT_DIR PLUGIN PROTOC_OPTION)
|
||||
if(COMMAND target_sources)
|
||||
list(APPEND _singleargs TARGET)
|
||||
endif()
|
||||
set(_multiargs PROTOS IMPORT_DIRS GENERATE_EXTENSIONS)
|
||||
|
||||
cmake_parse_arguments(protobuf_generate "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}")
|
||||
|
||||
if(NOT protobuf_generate_PROTOS AND NOT protobuf_generate_TARGET)
|
||||
message(SEND_ERROR "Error: protobuf_generate called without any targets or source files")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT protobuf_generate_OUT_VAR AND NOT protobuf_generate_TARGET)
|
||||
message(SEND_ERROR "Error: protobuf_generate called without a target or output variable")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(NOT protobuf_generate_LANGUAGE)
|
||||
set(protobuf_generate_LANGUAGE struct_pb)
|
||||
endif()
|
||||
string(TOLOWER ${protobuf_generate_LANGUAGE} protobuf_generate_LANGUAGE)
|
||||
|
||||
if(NOT protobuf_generate_PROTOC_OUT_DIR)
|
||||
set(protobuf_generate_PROTOC_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR})
|
||||
endif()
|
||||
|
||||
set(_opt)
|
||||
if(protobuf_generate_PROTOC_OPTION)
|
||||
set(_opt "${protobuf_generate_PROTOC_OPTION}")
|
||||
endif()
|
||||
if(protobuf_generate_EXPORT_MACRO AND protobuf_generate_LANGUAGE STREQUAL cpp)
|
||||
set(_opt "${opt},dllexport_decl=${protobuf_generate_EXPORT_MACRO}")
|
||||
endif()
|
||||
set(_opt "${_opt}:")
|
||||
if(protobuf_generate_PLUGIN)
|
||||
set(_plugin "--plugin=${protobuf_generate_PLUGIN}")
|
||||
endif()
|
||||
|
||||
if(NOT protobuf_generate_GENERATE_EXTENSIONS)
|
||||
if(protobuf_generate_LANGUAGE STREQUAL cpp)
|
||||
set(protobuf_generate_GENERATE_EXTENSIONS .pb.h .pb.cc)
|
||||
elseif(protobuf_generate_LANGUAGE STREQUAL python)
|
||||
set(protobuf_generate_GENERATE_EXTENSIONS _pb2.py)
|
||||
elseif(protobuf_generate_LANGUAGE STREQUAL struct_pb)
|
||||
set(protobuf_generate_GENERATE_EXTENSIONS .struct_pb.h .struct_pb.cc)
|
||||
else()
|
||||
message(SEND_ERROR "Error: protobuf_generate given unknown Language ${LANGUAGE}, please provide a value for GENERATE_EXTENSIONS")
|
||||
return()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if(protobuf_generate_TARGET)
|
||||
get_target_property(_source_list ${protobuf_generate_TARGET} SOURCES)
|
||||
foreach(_file ${_source_list})
|
||||
if(_file MATCHES "proto$")
|
||||
list(APPEND protobuf_generate_PROTOS ${_file})
|
||||
endif()
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if(NOT protobuf_generate_PROTOS)
|
||||
message(SEND_ERROR "Error: protobuf_generate could not find any .proto files")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(protobuf_generate_APPEND_PATH)
|
||||
# Create an include path for each file specified
|
||||
foreach(_file ${protobuf_generate_PROTOS})
|
||||
get_filename_component(_abs_file ${_file} ABSOLUTE)
|
||||
get_filename_component(_abs_path ${_abs_file} PATH)
|
||||
list(FIND _protobuf_include_path ${_abs_path} _contains_already)
|
||||
if(${_contains_already} EQUAL -1)
|
||||
list(APPEND _protobuf_include_path -I ${_abs_path})
|
||||
endif()
|
||||
endforeach()
|
||||
else()
|
||||
set(_protobuf_include_path -I ${CMAKE_CURRENT_SOURCE_DIR})
|
||||
endif()
|
||||
|
||||
foreach(DIR ${protobuf_generate_IMPORT_DIRS})
|
||||
get_filename_component(ABS_PATH ${DIR} ABSOLUTE)
|
||||
list(FIND _protobuf_include_path ${ABS_PATH} _contains_already)
|
||||
if(${_contains_already} EQUAL -1)
|
||||
list(APPEND _protobuf_include_path -I ${ABS_PATH})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(_generated_srcs_all)
|
||||
foreach(_proto ${protobuf_generate_PROTOS})
|
||||
get_filename_component(_abs_file ${_proto} ABSOLUTE)
|
||||
get_filename_component(_abs_dir ${_abs_file} DIRECTORY)
|
||||
get_filename_component(_basename ${_proto} NAME_WLE)
|
||||
file(RELATIVE_PATH _rel_dir ${CMAKE_CURRENT_SOURCE_DIR} ${_abs_dir})
|
||||
|
||||
set(_possible_rel_dir)
|
||||
if (NOT protobuf_generate_APPEND_PATH)
|
||||
set(_possible_rel_dir ${_rel_dir}/)
|
||||
endif()
|
||||
|
||||
set(_generated_srcs)
|
||||
foreach(_ext ${protobuf_generate_GENERATE_EXTENSIONS})
|
||||
list(APPEND _generated_srcs "${protobuf_generate_PROTOC_OUT_DIR}/${_possible_rel_dir}${_basename}${_ext}")
|
||||
endforeach()
|
||||
|
||||
if(protobuf_generate_DESCRIPTORS AND protobuf_generate_LANGUAGE STREQUAL cpp)
|
||||
set(_descriptor_file "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.desc")
|
||||
set(_dll_desc_out "--descriptor_set_out=${_descriptor_file}")
|
||||
list(APPEND _generated_srcs ${_descriptor_file})
|
||||
endif()
|
||||
list(APPEND _generated_srcs_all ${_generated_srcs})
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${_generated_srcs}
|
||||
COMMAND protobuf::protoc
|
||||
ARGS --${protobuf_generate_LANGUAGE}_out ${_opt}${protobuf_generate_PROTOC_OUT_DIR} ${_plugin} ${_dll_desc_out} ${_protobuf_include_path} ${_abs_file}
|
||||
DEPENDS ${_abs_file} protobuf::protoc
|
||||
COMMENT "Running ${protobuf_generate_LANGUAGE} protocol buffer compiler on ${_proto}"
|
||||
VERBATIM )
|
||||
endforeach()
|
||||
|
||||
set_source_files_properties(${_generated_srcs_all} PROPERTIES GENERATED TRUE)
|
||||
if(protobuf_generate_OUT_VAR)
|
||||
set(${protobuf_generate_OUT_VAR} ${_generated_srcs_all} PARENT_SCOPE)
|
||||
endif()
|
||||
if(protobuf_generate_TARGET)
|
||||
target_sources(${protobuf_generate_TARGET} PRIVATE ${_generated_srcs_all})
|
||||
target_include_directories(${protobuf_generate_TARGET} PUBLIC ${protobuf_generate_PROTOC_OUT_DIR})
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
|
||||
function(protobuf_generate_struct_pb SRCS HDRS)
|
||||
cmake_parse_arguments(protobuf_generate_struct_pb "" "EXPORT_MACRO;DESCRIPTORS;OPTION" "" ${ARGN})
|
||||
|
||||
set(_proto_files "${protobuf_generate_struct_pb_UNPARSED_ARGUMENTS}")
|
||||
if(NOT _proto_files)
|
||||
message(SEND_ERROR "Error: PROTOBUF_GENERATE_STRUCT_PB() called without any proto files")
|
||||
return()
|
||||
endif()
|
||||
|
||||
if(PROTOBUF_GENERATE_STRUCT_PB_APPEND_PATH)
|
||||
set(_append_arg APPEND_PATH)
|
||||
endif()
|
||||
|
||||
if(protobuf_generate_struct_pb_DESCRIPTORS)
|
||||
set(_descriptors DESCRIPTORS)
|
||||
endif()
|
||||
|
||||
if(protobuf_generate_struct_pb_OPTION)
|
||||
set(_opt ${protobuf_generate_struct_pb_OPTION})
|
||||
endif()
|
||||
|
||||
if(DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
|
||||
set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
|
||||
endif()
|
||||
|
||||
if(DEFINED Protobuf_IMPORT_DIRS)
|
||||
set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
|
||||
endif()
|
||||
|
||||
set(_outvar)
|
||||
protobuf_generate_modified(${_append_arg} ${_descriptors}
|
||||
LANGUAGE struct_pb EXPORT_MACRO ${protobuf_generate_struct_pb_EXPORT_MACRO}
|
||||
PLUGIN $<TARGET_FILE:protoc-gen-struct_pb>
|
||||
OUT_VAR _outvar ${_import_arg} PROTOS ${_proto_files}
|
||||
PROTOC_OPTION ${_opt}
|
||||
)
|
||||
|
||||
set(${SRCS})
|
||||
set(${HDRS})
|
||||
if(protobuf_generate_struct_pb_DESCRIPTORS)
|
||||
set(${protobuf_generate_struct_pb_DESCRIPTORS})
|
||||
endif()
|
||||
|
||||
foreach(_file ${_outvar})
|
||||
if(_file MATCHES "cc$")
|
||||
list(APPEND ${SRCS} ${_file})
|
||||
elseif(_file MATCHES "desc$")
|
||||
list(APPEND ${protobuf_generate_struct_pb_DESCRIPTORS} ${_file})
|
||||
else()
|
||||
list(APPEND ${HDRS} ${_file})
|
||||
endif()
|
||||
endforeach()
|
||||
set(${SRCS} ${${SRCS}} PARENT_SCOPE)
|
||||
set(${HDRS} ${${HDRS}} PARENT_SCOPE)
|
||||
if(protobuf_generate_struct_pb_DESCRIPTORS)
|
||||
set(${protobuf_generate_struct_pb_DESCRIPTORS} "${${protobuf_generate_struct_pb_DESCRIPTORS}}" PARENT_SCOPE)
|
||||
endif()
|
||||
endfunction()
|
||||
|
||||
function(target_protos_struct_pb target)
|
||||
set(_options APPEND_PATH DESCRIPTORS)
|
||||
set(_singleargs LANGUAGE EXPORT_MACRO PROTOC_OUT_DIR PLUGIN OPTION)
|
||||
set(_multiargs IMPORT_DIRS PRIVATE PUBLIC)
|
||||
cmake_parse_arguments(target_protos_struct_pb "${_options}" "${_singleargs}" "${_multiargs}" "${ARGN}")
|
||||
set(_proto_files "${target_protos_struct_pb_PRIVATE}" "${target_protos_struct_pb_PUBLIC}")
|
||||
if (NOT _proto_files)
|
||||
message(SEND_ERROR "Error: TARGET_PROTOS_STRUCT_PB() called without any proto files")
|
||||
return()
|
||||
endif ()
|
||||
|
||||
if (DEFINED PROTOBUF_IMPORT_DIRS AND NOT DEFINED Protobuf_IMPORT_DIRS)
|
||||
set(Protobuf_IMPORT_DIRS "${PROTOBUF_IMPORT_DIRS}")
|
||||
endif ()
|
||||
|
||||
if (DEFINED Protobuf_IMPORT_DIRS)
|
||||
set(_import_arg IMPORT_DIRS ${Protobuf_IMPORT_DIRS})
|
||||
endif ()
|
||||
|
||||
if (target_protos_struct_pb_OPTION)
|
||||
set(_opt ${target_protos_struct_pb_OPTION})
|
||||
endif ()
|
||||
protobuf_generate_modified(
|
||||
TARGET ${target}
|
||||
LANGUAGE struct_pb EXPORT_MACRO ${target_protos_struct_pb_EXPORT_MACRO}
|
||||
PLUGIN $<TARGET_FILE:protoc-gen-struct_pb>
|
||||
${_import_arg} PROTOS ${_proto_files}
|
||||
PROTOC_OPTION ${_opt}
|
||||
)
|
||||
endfunction()
|
||||
|
|
@ -22,13 +22,13 @@ endif()
|
|||
foreach(child ${children})
|
||||
get_filename_component(subdir_name ${child} NAME)
|
||||
string(TOUPPER ${subdir_name} subdir_name)
|
||||
message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}")
|
||||
endforeach()
|
||||
if((${subdir_name} STREQUAL "STRUCT_PACK" OR ${subdir_name} STREQUAL "STRUCT_PB") AND (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC"))
|
||||
message(STATUS "skip ${subdir_name}")
|
||||
continue()
|
||||
endif()
|
||||
|
||||
foreach(child ${children})
|
||||
get_filename_component(subdir_name ${child} NAME)
|
||||
string(TOUPPER ${subdir_name} subdir_name)
|
||||
if (BUILD_${subdir_name})
|
||||
message(STATUS "BUILD_${subdir_name}: ${BUILD_${subdir_name}}")
|
||||
if(BUILD_EXAMPLES AND EXISTS ${child}/examples)
|
||||
add_subdirectory(${child}/examples)
|
||||
endif()
|
||||
|
|
@ -40,7 +40,4 @@ foreach(child ${children})
|
|||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
if (BUILD_STRUCT_PB)
|
||||
add_subdirectory(src/struct_pb)
|
||||
endif()
|
||||
message(STATUS "--------------------------------------------")
|
||||
|
|
@ -0,0 +1,135 @@
|
|||
#pragma once
|
||||
|
||||
namespace iguana {
|
||||
|
||||
struct sint32_t {
|
||||
using value_type = int32_t;
|
||||
int32_t val;
|
||||
bool operator==(const sint32_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(sint32_t value1, int32_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
// for key in std::map
|
||||
inline bool operator<(const sint32_t& lhs, const sint32_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
struct sint64_t {
|
||||
using value_type = int64_t;
|
||||
int64_t val;
|
||||
bool operator==(const sint64_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(sint64_t value1, int64_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
inline bool operator<(const sint64_t& lhs, const sint64_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
struct fixed32_t {
|
||||
using value_type = uint32_t;
|
||||
uint32_t val;
|
||||
bool operator==(const fixed32_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(fixed32_t value1, uint32_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
inline bool operator<(const fixed32_t& lhs, const fixed32_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
struct fixed64_t {
|
||||
using value_type = uint64_t;
|
||||
uint64_t val;
|
||||
bool operator==(const fixed64_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(fixed64_t value1, uint64_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
inline bool operator<(const fixed64_t& lhs, const fixed64_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
struct sfixed32_t {
|
||||
using value_type = int32_t;
|
||||
int32_t val;
|
||||
bool operator==(const sfixed32_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(sfixed32_t value1, int32_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
inline bool operator<(const sfixed32_t& lhs, const sfixed32_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
struct sfixed64_t {
|
||||
using value_type = int64_t;
|
||||
int64_t val;
|
||||
bool operator==(const sfixed64_t& other) const { return val == other.val; }
|
||||
};
|
||||
|
||||
inline bool operator==(sfixed64_t value1, int64_t value2) {
|
||||
return value1.val == value2;
|
||||
}
|
||||
|
||||
inline bool operator<(const sfixed64_t& lhs, const sfixed64_t& rhs) {
|
||||
return lhs.val < rhs.val;
|
||||
}
|
||||
|
||||
} // namespace iguana
|
||||
|
||||
// for key in std::unordered_map
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<iguana::sint32_t> {
|
||||
size_t operator()(const iguana::sint32_t& x) const noexcept {
|
||||
return std::hash<int32_t>()(x.val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<iguana::sint64_t> {
|
||||
size_t operator()(const iguana::sint64_t& x) const noexcept {
|
||||
return std::hash<int64_t>()(x.val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<iguana::fixed32_t> {
|
||||
size_t operator()(const iguana::fixed32_t& x) const noexcept {
|
||||
return std::hash<uint32_t>()(x.val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<iguana::fixed64_t> {
|
||||
size_t operator()(const iguana::fixed64_t& x) const noexcept {
|
||||
return std::hash<uint64_t>()(x.val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<iguana::sfixed32_t> {
|
||||
size_t operator()(const iguana::sfixed32_t& x) const noexcept {
|
||||
return std::hash<int32_t>()(x.val);
|
||||
}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct hash<iguana::sfixed64_t> {
|
||||
size_t operator()(const iguana::sfixed64_t& x) const noexcept {
|
||||
return std::hash<int64_t>()(x.val);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
|
@ -0,0 +1,131 @@
|
|||
#pragma once
|
||||
#include <cstddef>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
namespace iguana::detail {
|
||||
|
||||
#if __cpp_lib_string_resize_and_overwrite >= 202110L
|
||||
template <typename ch>
|
||||
inline void resize(std::basic_string<ch> &str, std::size_t sz) {
|
||||
str.resize_and_overwrite(sz, [sz](ch *, std::size_t) {
|
||||
return sz;
|
||||
});
|
||||
}
|
||||
#elif (defined(_MSC_VER) && _MSC_VER <= 1920)
|
||||
// old msvc don't support visit private, discard it.
|
||||
|
||||
#else
|
||||
|
||||
template <typename Function, Function func_ptr>
|
||||
class string_thief {
|
||||
public:
|
||||
friend void string_set_length_hacker(std::string &self, std::size_t sz) {
|
||||
#if defined(_MSVC_STL_VERSION)
|
||||
(self.*func_ptr)._Myval2._Mysize = sz;
|
||||
#else
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
(self.*func_ptr)(sz);
|
||||
#else
|
||||
#if (_GLIBCXX_USE_CXX11_ABI == 0) && defined(__GLIBCXX__)
|
||||
(self.*func_ptr)()->_M_set_length_and_sharable(sz);
|
||||
#else
|
||||
#if defined(__GLIBCXX__)
|
||||
(self.*func_ptr)(sz);
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GLIBCXX__) // libstdc++
|
||||
#if (_GLIBCXX_USE_CXX11_ABI == 0)
|
||||
template class string_thief<decltype(&std::string::_M_rep),
|
||||
&std::string::_M_rep>;
|
||||
#else
|
||||
template class string_thief<decltype(&std::string::_M_set_length),
|
||||
&std::string::_M_set_length>;
|
||||
#endif
|
||||
#elif defined(_LIBCPP_VERSION)
|
||||
template class string_thief<decltype(&std::string::__set_size),
|
||||
&std::string::__set_size>;
|
||||
#elif defined(_MSVC_STL_VERSION)
|
||||
template class string_thief<decltype(&std::string::_Mypair),
|
||||
&std::string::_Mypair>;
|
||||
#endif
|
||||
|
||||
void string_set_length_hacker(std::string &, std::size_t);
|
||||
|
||||
template <typename ch>
|
||||
inline void resize(std::basic_string<ch> &raw_str, std::size_t sz) {
|
||||
std::string &str = *reinterpret_cast<std::string *>(&raw_str);
|
||||
#if defined(__GLIBCXX__) || defined(_LIBCPP_VERSION) || \
|
||||
defined(_MSVC_STL_VERSION)
|
||||
if (sz > str.capacity()) {
|
||||
str.reserve(sz);
|
||||
}
|
||||
string_set_length_hacker(str, sz);
|
||||
str[sz] = '\0';
|
||||
#else
|
||||
raw_str.resize(sz);
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#if (defined(_MSC_VER) && _MSC_VER <= 1920)
|
||||
#else
|
||||
void vector_set_length_hacker(std::vector<char> &self, std::size_t sz);
|
||||
|
||||
template <typename Function, Function func_ptr>
|
||||
class vector_thief {
|
||||
public:
|
||||
friend void vector_set_length_hacker(std::vector<char> &self,
|
||||
std::size_t sz) {
|
||||
#if defined(_MSVC_STL_VERSION)
|
||||
(self.*func_ptr)._Myval2._Mylast = self.data() + sz;
|
||||
#else
|
||||
#if defined(_LIBCPP_VERSION)
|
||||
#if _LIBCPP_VERSION < 14000
|
||||
((*(std::__vector_base<char, std::allocator<char> > *)(&self)).*func_ptr) =
|
||||
self.data() + sz;
|
||||
#else
|
||||
(self.*func_ptr) = self.data() + sz;
|
||||
#endif
|
||||
#else
|
||||
#if defined(__GLIBCXX__)
|
||||
((*(std::_Vector_base<char, std::allocator<char> > *)(&self)).*func_ptr)
|
||||
._M_finish = self.data() + sz;
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
#if defined(__GLIBCXX__) // libstdc++
|
||||
template class vector_thief<decltype(&std::vector<char>::_M_impl),
|
||||
&std::vector<char>::_M_impl>;
|
||||
#elif defined(_LIBCPP_VERSION)
|
||||
template class vector_thief<decltype(&std::vector<char>::__end_),
|
||||
&std::vector<char>::__end_>;
|
||||
#elif defined(_MSVC_STL_VERSION)
|
||||
template class vector_thief<decltype(&std::vector<char>::_Mypair),
|
||||
&std::vector<char>::_Mypair>;
|
||||
#endif
|
||||
|
||||
template <typename ch>
|
||||
inline void resize(std::vector<ch> &raw_vec, std::size_t sz) {
|
||||
#if defined(__GLIBCXX__) || \
|
||||
(defined(_LIBCPP_VERSION) && defined(_LIBCPP_HAS_NO_ASAN)) || \
|
||||
defined(_MSVC_STL_VERSION)
|
||||
std::vector<char> &vec = *reinterpret_cast<std::vector<char> *>(&raw_vec);
|
||||
vec.reserve(sz);
|
||||
vector_set_length_hacker(vec, sz);
|
||||
#else
|
||||
raw_vec.resize(sz);
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
}; // namespace iguana::detail
|
||||
|
|
@ -79,5 +79,39 @@ struct member_tratis<T Owner::*> {
|
|||
template <typename T>
|
||||
inline constexpr bool is_int64_v =
|
||||
std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>;
|
||||
|
||||
template <typename T>
|
||||
struct is_variant : std::false_type {};
|
||||
|
||||
template <typename... T>
|
||||
struct is_variant<std::variant<T...>> : std::true_type {};
|
||||
|
||||
template <class T>
|
||||
struct member_traits {
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
template <class T, class Owner>
|
||||
struct member_traits<T Owner::*> {
|
||||
using owner_type = Owner;
|
||||
using value_type = T;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
using member_value_type_t = typename member_traits<T>::value_type;
|
||||
|
||||
template <typename T, std::size_t I, typename = void>
|
||||
struct variant_type_at {
|
||||
using type = T;
|
||||
};
|
||||
|
||||
template <typename T, std::size_t I>
|
||||
struct variant_type_at<T, I, std::enable_if_t<is_variant<T>::value>> {
|
||||
using type = std::variant_alternative_t<I, T>;
|
||||
};
|
||||
template <typename T, std::size_t I>
|
||||
using variant_type_at_t =
|
||||
typename variant_type_at<typename member_traits<T>::value_type, I>::type;
|
||||
|
||||
} // namespace iguana
|
||||
#endif // SERIALIZE_TRAITS_HPP
|
||||
|
|
|
|||
|
|
@ -0,0 +1,257 @@
|
|||
#pragma once
|
||||
#include "detail/string_resize.hpp"
|
||||
#include "pb_util.hpp"
|
||||
|
||||
namespace iguana {
|
||||
|
||||
namespace detail {
|
||||
|
||||
template <typename T>
|
||||
IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str,
|
||||
uint32_t field_no = 0);
|
||||
|
||||
template <typename T>
|
||||
IGUANA_INLINE void decode_pair_value(T& val, std::string_view& pb_str) {
|
||||
size_t pos;
|
||||
uint32_t key = detail::decode_varint(pb_str, pos);
|
||||
pb_str = pb_str.substr(pos);
|
||||
WireType wire_type = static_cast<WireType>(key & 0b0111);
|
||||
if (wire_type != detail::get_wire_type<std::remove_reference_t<T>>()) {
|
||||
return;
|
||||
}
|
||||
from_pb_impl(val, pb_str);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
IGUANA_INLINE void from_pb_impl(T& val, std::string_view& pb_str,
|
||||
uint32_t field_no) {
|
||||
size_t pos = 0;
|
||||
if constexpr (is_reflection_v<T>) {
|
||||
size_t pos;
|
||||
uint32_t size = detail::decode_varint(pb_str, pos);
|
||||
pb_str = pb_str.substr(pos);
|
||||
if (pb_str.size() < size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument("Invalid fixed int value: too few bytes.");
|
||||
}
|
||||
if (size == 0) {
|
||||
return;
|
||||
}
|
||||
from_pb(val, pb_str.substr(0, size));
|
||||
pb_str = pb_str.substr(size);
|
||||
}
|
||||
else if constexpr (is_sequence_container<T>::value) {
|
||||
using item_type = typename T::value_type;
|
||||
if constexpr (is_lenprefix_v<item_type>) {
|
||||
// item_type non-packed
|
||||
while (!pb_str.empty()) {
|
||||
item_type item{};
|
||||
from_pb_impl(item, pb_str);
|
||||
val.push_back(std::move(item));
|
||||
if (pb_str.empty()) {
|
||||
break;
|
||||
}
|
||||
uint32_t key = detail::decode_varint(pb_str, pos);
|
||||
uint32_t field_number = key >> 3;
|
||||
if (field_number != field_no) {
|
||||
break;
|
||||
}
|
||||
else {
|
||||
pb_str = pb_str.substr(pos);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
// item_type packed
|
||||
size_t pos;
|
||||
uint32_t size = detail::decode_varint(pb_str, pos);
|
||||
pb_str = pb_str.substr(pos);
|
||||
if (pb_str.size() < size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument(
|
||||
"Invalid fixed int value: too few bytes.");
|
||||
}
|
||||
using item_type = typename T::value_type;
|
||||
size_t start = pb_str.size();
|
||||
|
||||
while (!pb_str.empty()) {
|
||||
item_type item;
|
||||
from_pb_impl(item, pb_str);
|
||||
val.push_back(std::move(item));
|
||||
if (start - pb_str.size() == size) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (is_map_container<T>::value) {
|
||||
using item_type = std::pair<typename T::key_type, typename T::mapped_type>;
|
||||
while (!pb_str.empty()) {
|
||||
size_t pos;
|
||||
uint32_t size = detail::decode_varint(pb_str, pos);
|
||||
pb_str = pb_str.substr(pos);
|
||||
if (pb_str.size() < size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument(
|
||||
"Invalid fixed int value: too few bytes.");
|
||||
}
|
||||
item_type item = {};
|
||||
decode_pair_value(item.first, pb_str);
|
||||
decode_pair_value(item.second, pb_str);
|
||||
val.emplace(std::move(item));
|
||||
|
||||
if (pb_str.empty()) {
|
||||
break;
|
||||
}
|
||||
uint32_t key = detail::decode_varint(pb_str, pos);
|
||||
uint32_t field_number = key >> 3;
|
||||
if (field_number != field_no) {
|
||||
break;
|
||||
}
|
||||
pb_str = pb_str.substr(pos);
|
||||
}
|
||||
}
|
||||
else if constexpr (std::is_integral_v<T>) {
|
||||
val = static_cast<T>(detail::decode_varint(pb_str, pos));
|
||||
pb_str = pb_str.substr(pos);
|
||||
}
|
||||
else if constexpr (detail::is_signed_varint_v<T>) {
|
||||
constexpr size_t len = sizeof(typename T::value_type);
|
||||
uint64_t temp = detail::decode_varint(pb_str, pos);
|
||||
if constexpr (len == 8) {
|
||||
val.val = detail::decode_zigzag(temp);
|
||||
}
|
||||
else {
|
||||
val.val = detail::decode_zigzag(static_cast<uint32_t>(temp));
|
||||
}
|
||||
pb_str = pb_str.substr(pos);
|
||||
}
|
||||
else if constexpr (detail::is_fixed_v<T>) {
|
||||
constexpr size_t size = sizeof(typename T::value_type);
|
||||
if (pb_str.size() < size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument("Invalid fixed int value: too few bytes.");
|
||||
}
|
||||
memcpy(&(val.val), pb_str.data(), size);
|
||||
pb_str = pb_str.substr(size);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double> || std::is_same_v<T, float>) {
|
||||
constexpr size_t size = sizeof(T);
|
||||
if (pb_str.size() < size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument("Invalid fixed int value: too few bytes.");
|
||||
}
|
||||
memcpy(&(val), pb_str.data(), size);
|
||||
pb_str = pb_str.substr(size);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string> ||
|
||||
std::is_same_v<T, std::string_view>) {
|
||||
size_t size = detail::decode_varint(pb_str, pos);
|
||||
if (pb_str.size() < pos + size)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument("Invalid string value: too few bytes.");
|
||||
}
|
||||
if constexpr (std::is_same_v<T, std::string_view>) {
|
||||
val = std::string_view(pb_str.data() + pos, size);
|
||||
}
|
||||
else {
|
||||
detail::resize(val, size);
|
||||
memcpy(val.data(), pb_str.data() + pos, size);
|
||||
}
|
||||
pb_str = pb_str.substr(size + pos);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>) {
|
||||
using U = std::underlying_type_t<T>;
|
||||
U value{};
|
||||
from_pb_impl(value, pb_str);
|
||||
val = static_cast<T>(value);
|
||||
}
|
||||
else if constexpr (optional_v<T>) {
|
||||
from_pb_impl(val.emplace(), pb_str);
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "err");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename Field>
|
||||
IGUANA_INLINE void parse_oneof(T& t, const Field& f, std::string_view& pb_str) {
|
||||
using item_type = typename std::decay_t<Field>::sub_type;
|
||||
from_pb_impl(t.template emplace<item_type>(), pb_str, f.field_no);
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename T>
|
||||
IGUANA_INLINE void from_pb(T& t, std::string_view pb_str) {
|
||||
if (pb_str.empty())
|
||||
IGUANA_UNLIKELY { return; }
|
||||
size_t pos = 0;
|
||||
uint32_t key = detail::decode_varint(pb_str, pos);
|
||||
WireType wire_type = static_cast<WireType>(key & 0b0111);
|
||||
uint32_t field_number = key >> 3;
|
||||
#ifdef SEQUENTIAL_PARSE
|
||||
constexpr static auto tp = get_members_tuple<T>();
|
||||
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tp)>>;
|
||||
bool parse_done = false;
|
||||
detail::for_each_n(
|
||||
[&](auto i) IGUANA__INLINE_LAMBDA {
|
||||
constexpr auto val = std::get<decltype(i)::value>(tp);
|
||||
using sub_type = typename std::decay_t<decltype(val)>::sub_type;
|
||||
using value_type = typename std::decay_t<decltype(val)>::value_type;
|
||||
// sub_type is the element type when value_type is the variant type;
|
||||
// otherwise, they are the same.
|
||||
if (parse_done || field_number != val.field_no) {
|
||||
return;
|
||||
}
|
||||
pb_str = pb_str.substr(pos);
|
||||
if (wire_type != detail::get_wire_type<sub_type>())
|
||||
IGUANA_UNLIKELY { throw std::runtime_error("unmatched wire_type"); }
|
||||
if constexpr (variant_v<value_type>) {
|
||||
detail::parse_oneof(val.value(t), val, pb_str);
|
||||
}
|
||||
else {
|
||||
detail::from_pb_impl(val.value(t), pb_str, val.field_no);
|
||||
}
|
||||
if (pb_str.empty()) {
|
||||
parse_done = true;
|
||||
return;
|
||||
}
|
||||
key = detail::decode_varint(pb_str, pos);
|
||||
wire_type = static_cast<WireType>(key & 0b0111);
|
||||
field_number = key >> 3;
|
||||
},
|
||||
std::make_index_sequence<SIZE>{});
|
||||
if (parse_done)
|
||||
IGUANA_LIKELY { return; }
|
||||
#endif
|
||||
while (true) {
|
||||
pb_str = pb_str.substr(pos);
|
||||
constexpr static auto map = get_members<T>();
|
||||
auto& member = map.at(field_number);
|
||||
std::visit(
|
||||
[&t, &pb_str, wire_type](auto& val) {
|
||||
using sub_type = typename std::decay_t<decltype(val)>::sub_type;
|
||||
using value_type = typename std::decay_t<decltype(val)>::value_type;
|
||||
if (wire_type != detail::get_wire_type<sub_type>()) {
|
||||
throw std::runtime_error("unmatched wire_type");
|
||||
}
|
||||
if constexpr (variant_v<value_type>) {
|
||||
detail::parse_oneof(val.value(t), val, pb_str);
|
||||
}
|
||||
else {
|
||||
detail::from_pb_impl(val.value(t), pb_str, val.field_no);
|
||||
}
|
||||
},
|
||||
member);
|
||||
if (!pb_str.empty())
|
||||
IGUANA_LIKELY {
|
||||
key = detail::decode_varint(pb_str, pos);
|
||||
wire_type = static_cast<WireType>(key & 0b0111);
|
||||
field_number = key >> 3;
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace iguana
|
||||
|
|
@ -0,0 +1,660 @@
|
|||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <type_traits>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "detail/pb_type.hpp"
|
||||
#include "reflection.hpp"
|
||||
#include "util.hpp"
|
||||
|
||||
namespace iguana {
|
||||
|
||||
enum class WireType : uint32_t {
|
||||
Varint = 0,
|
||||
Fixed64 = 1,
|
||||
LengthDelimeted = 2,
|
||||
StartGroup = 3,
|
||||
EndGroup = 4,
|
||||
Fixed32 = 5,
|
||||
Unknown
|
||||
};
|
||||
|
||||
template <typename T, typename Stream>
|
||||
IGUANA_INLINE void to_pb(T& t, Stream& out);
|
||||
|
||||
template <typename T>
|
||||
IGUANA_INLINE void from_pb(T& t, std::string_view pb_str);
|
||||
|
||||
using base = detail::base;
|
||||
|
||||
template <typename T, typename U>
|
||||
IGUANA_INLINE constexpr size_t member_offset(T* t, U T::*member) {
|
||||
return (char*)&(t->*member) - (char*)t;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
struct base_impl : public base {
|
||||
void to_pb(std::string& str) override {
|
||||
iguana::to_pb(*(static_cast<T*>(this)), str);
|
||||
}
|
||||
|
||||
void from_pb(std::string_view str) override {
|
||||
iguana::from_pb(*(static_cast<T*>(this)), str);
|
||||
}
|
||||
|
||||
iguana::detail::field_info get_field_info(std::string_view name) override {
|
||||
static constexpr auto map = iguana::get_members<T>();
|
||||
iguana::detail::field_info info{};
|
||||
for (auto [no, field] : map) {
|
||||
if (info.offset > 0) {
|
||||
break;
|
||||
}
|
||||
std::visit(
|
||||
[&](auto val) {
|
||||
if (val.field_name == name) {
|
||||
info.offset = member_offset((T*)this, val.member_ptr);
|
||||
using value_type = typename decltype(val)::value_type;
|
||||
#if defined(__clang__) || defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && __GNUC__ > 8)
|
||||
info.type_name = type_string<value_type>();
|
||||
#endif
|
||||
}
|
||||
},
|
||||
field);
|
||||
}
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
std::vector<std::string_view> get_fields_name() override {
|
||||
static constexpr auto map = iguana::get_members<T>();
|
||||
std::vector<std::string_view> vec;
|
||||
for (auto [no, val] : map) {
|
||||
std::visit(
|
||||
[&](auto& field) {
|
||||
vec.push_back(std::string_view(field.field_name.data(),
|
||||
field.field_name.size()));
|
||||
},
|
||||
val);
|
||||
}
|
||||
return vec;
|
||||
}
|
||||
|
||||
virtual ~base_impl() {}
|
||||
|
||||
size_t cache_size = 0;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool inherits_from_base_v = std::is_base_of_v<base, T>;
|
||||
|
||||
IGUANA_INLINE std::shared_ptr<base> create_instance(std::string_view name) {
|
||||
auto it = iguana::detail::g_pb_map.find(name);
|
||||
if (it == iguana::detail::g_pb_map.end()) {
|
||||
throw std::invalid_argument(std::string(name) +
|
||||
"not inheried from iguana::base_impl");
|
||||
}
|
||||
return it->second();
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
template <typename T>
|
||||
constexpr bool is_fixed_v =
|
||||
std::is_same_v<T, fixed32_t> || std::is_same_v<T, fixed64_t> ||
|
||||
std::is_same_v<T, sfixed32_t> || std::is_same_v<T, sfixed64_t>;
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_signed_varint_v =
|
||||
std::is_same_v<T, sint32_t> || std::is_same_v<T, sint64_t>;
|
||||
|
||||
template <typename T>
|
||||
constexpr inline WireType get_wire_type() {
|
||||
if constexpr (std::is_integral_v<T> || is_signed_varint_v<T> ||
|
||||
std::is_enum_v<T> || std::is_same_v<T, bool>) {
|
||||
return WireType::Varint;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, fixed32_t> ||
|
||||
std::is_same_v<T, sfixed32_t> ||
|
||||
std::is_same_v<T, float>) {
|
||||
return WireType::Fixed32;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, fixed64_t> ||
|
||||
std::is_same_v<T, sfixed64_t> ||
|
||||
std::is_same_v<T, double>) {
|
||||
return WireType::Fixed64;
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string> ||
|
||||
std::is_same_v<T, std::string_view> ||
|
||||
is_reflection_v<T> || is_sequence_container<T>::value ||
|
||||
is_map_container<T>::value) {
|
||||
return WireType::LengthDelimeted;
|
||||
}
|
||||
else if constexpr (optional_v<T>) {
|
||||
return get_wire_type<typename T::value_type>();
|
||||
}
|
||||
else {
|
||||
throw std::runtime_error("unknown type");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_lenprefix_v = (get_wire_type<T>() ==
|
||||
WireType::LengthDelimeted);
|
||||
|
||||
[[nodiscard]] IGUANA_INLINE uint32_t encode_zigzag(int32_t v) {
|
||||
return (static_cast<uint32_t>(v) << 1U) ^
|
||||
static_cast<uint32_t>(
|
||||
-static_cast<int32_t>(static_cast<uint32_t>(v) >> 31U));
|
||||
}
|
||||
[[nodiscard]] IGUANA_INLINE uint64_t encode_zigzag(int64_t v) {
|
||||
return (static_cast<uint64_t>(v) << 1U) ^
|
||||
static_cast<uint64_t>(
|
||||
-static_cast<int64_t>(static_cast<uint64_t>(v) >> 63U));
|
||||
}
|
||||
|
||||
[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint64_t u) {
|
||||
return static_cast<int64_t>((u >> 1U)) ^
|
||||
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
|
||||
}
|
||||
[[nodiscard]] IGUANA_INLINE int64_t decode_zigzag(uint32_t u) {
|
||||
return static_cast<int64_t>((u >> 1U)) ^
|
||||
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
|
||||
}
|
||||
|
||||
template <class T>
|
||||
IGUANA_INLINE uint64_t decode_varint(T& data, size_t& pos) {
|
||||
const int8_t* begin = reinterpret_cast<const int8_t*>(data.data());
|
||||
const int8_t* end = begin + data.size();
|
||||
const int8_t* p = begin;
|
||||
uint64_t val = 0;
|
||||
|
||||
if ((static_cast<uint64_t>(*p) & 0x80) == 0) {
|
||||
pos = 1;
|
||||
return static_cast<uint64_t>(*p);
|
||||
}
|
||||
|
||||
// end is always greater than or equal to begin, so this subtraction is safe
|
||||
if (size_t(end - begin) >= 10)
|
||||
IGUANA_LIKELY { // fast path
|
||||
int64_t b;
|
||||
do {
|
||||
b = *p++;
|
||||
val = (b & 0x7f);
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 7;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 14;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 21;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 28;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 35;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 42;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 49;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x7f) << 56;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
b = *p++;
|
||||
val |= (b & 0x01) << 63;
|
||||
if (b >= 0) {
|
||||
break;
|
||||
}
|
||||
throw std::invalid_argument("Invalid varint value: too many bytes.");
|
||||
} while (false);
|
||||
}
|
||||
else {
|
||||
int shift = 0;
|
||||
while (p != end && *p < 0) {
|
||||
val |= static_cast<uint64_t>(*p++ & 0x7f) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
if (p == end)
|
||||
IGUANA_UNLIKELY {
|
||||
throw std::invalid_argument("Invalid varint value: too few bytes.");
|
||||
}
|
||||
val |= static_cast<uint64_t>(*p++) << shift;
|
||||
}
|
||||
|
||||
pos = (p - begin);
|
||||
return val;
|
||||
}
|
||||
|
||||
// value == 0 ? 1 : floor(log2(value)) / 7 + 1
|
||||
constexpr size_t variant_uint32_size_constexpr(uint32_t value) {
|
||||
if (value == 0) {
|
||||
return 1;
|
||||
}
|
||||
int log = 0;
|
||||
while (value >>= 1) ++log;
|
||||
return log / 7 + 1;
|
||||
}
|
||||
|
||||
template <uint64_t v, size_t I, typename It>
|
||||
IGUANA_INLINE void append_varint_u32_constexpr_help(It&& it) {
|
||||
*(it++) = static_cast<uint8_t>((v >> (7 * I)) | 0x80);
|
||||
}
|
||||
|
||||
template <uint64_t v, typename It, size_t... I>
|
||||
IGUANA_INLINE void append_varint_u32_constexpr(It&& it,
|
||||
std::index_sequence<I...>) {
|
||||
(append_varint_u32_constexpr_help<v, I>(it), ...);
|
||||
}
|
||||
|
||||
template <uint32_t v, typename It>
|
||||
IGUANA_INLINE void serialize_varint_u32_constexpr(It&& it) {
|
||||
constexpr auto size = variant_uint32_size_constexpr(v);
|
||||
append_varint_u32_constexpr<v>(it, std::make_index_sequence<size - 1>{});
|
||||
*(it++) = static_cast<uint8_t>(v >> (7 * (size - 1)));
|
||||
}
|
||||
|
||||
template <typename It>
|
||||
IGUANA_INLINE void serialize_varint(uint64_t v, It&& it) {
|
||||
if (v < 0x80) {
|
||||
*(it++) = static_cast<uint8_t>(v);
|
||||
return;
|
||||
}
|
||||
*(it++) = static_cast<uint8_t>(v | 0x80);
|
||||
v >>= 7;
|
||||
if (v < 0x80) {
|
||||
*(it++) = static_cast<uint8_t>(v);
|
||||
return;
|
||||
}
|
||||
do {
|
||||
*(it++) = static_cast<uint8_t>(v | 0x80);
|
||||
v >>= 7;
|
||||
} while (v >= 0x80);
|
||||
*(it++) = static_cast<uint8_t>(v);
|
||||
}
|
||||
|
||||
IGUANA_INLINE uint32_t log2_floor_uint32(uint32_t n) {
|
||||
#if defined(__GNUC__)
|
||||
return 31 ^ static_cast<uint32_t>(__builtin_clz(n));
|
||||
#else
|
||||
unsigned long where;
|
||||
_BitScanReverse(&where, n);
|
||||
return where;
|
||||
#endif
|
||||
}
|
||||
|
||||
IGUANA_INLINE size_t variant_uint32_size(uint32_t value) {
|
||||
// This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
|
||||
// Use an explicit multiplication to implement the divide of
|
||||
// a number in the 1..31 range.
|
||||
// Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
|
||||
// undefined.
|
||||
uint32_t log2value = log2_floor_uint32(value | 0x1);
|
||||
return static_cast<size_t>((log2value * 9 + 73) / 64);
|
||||
}
|
||||
|
||||
IGUANA_INLINE int Log2FloorNonZero_Portable(uint32_t n) {
|
||||
if (n == 0)
|
||||
return -1;
|
||||
int log = 0;
|
||||
uint32_t value = n;
|
||||
for (int i = 4; i >= 0; --i) {
|
||||
int shift = (1 << i);
|
||||
uint32_t x = value >> shift;
|
||||
if (x != 0) {
|
||||
value = x;
|
||||
log += shift;
|
||||
}
|
||||
}
|
||||
assert(value == 1);
|
||||
return log;
|
||||
}
|
||||
|
||||
IGUANA_INLINE uint32_t Log2FloorNonZero(uint32_t n) {
|
||||
#if defined(__GNUC__)
|
||||
return 31 ^ static_cast<uint32_t>(__builtin_clz(n));
|
||||
#elif defined(_MSC_VER)
|
||||
unsigned long where;
|
||||
_BitScanReverse(&where, n);
|
||||
return where;
|
||||
#else
|
||||
return Log2FloorNonZero_Portable(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
IGUANA_INLINE int Log2FloorNonZero64_Portable(uint64_t n) {
|
||||
const uint32_t topbits = static_cast<uint32_t>(n >> 32);
|
||||
if (topbits == 0) {
|
||||
// Top bits are zero, so scan in bottom bits
|
||||
return static_cast<int>(Log2FloorNonZero(static_cast<uint32_t>(n)));
|
||||
}
|
||||
else {
|
||||
return 32 + static_cast<int>(Log2FloorNonZero(topbits));
|
||||
}
|
||||
}
|
||||
|
||||
IGUANA_INLINE uint32_t log2_floor_uint64(uint64_t n) {
|
||||
#if defined(__GNUC__)
|
||||
return 63 ^ static_cast<uint32_t>(__builtin_clzll(n));
|
||||
#elif defined(_MSC_VER) && defined(_M_X64)
|
||||
unsigned long where;
|
||||
_BitScanReverse64(&where, n);
|
||||
return where;
|
||||
#else
|
||||
return Log2FloorNonZero64_Portable(n);
|
||||
#endif
|
||||
}
|
||||
|
||||
IGUANA_INLINE size_t variant_uint64_size(uint64_t value) {
|
||||
// This computes value == 0 ? 1 : floor(log2(value)) / 7 + 1
|
||||
// Use an explicit multiplication to implement the divide of
|
||||
// a number in the 1..63 range.
|
||||
// Explicit OR 0x1 to avoid calling Bits::Log2FloorNonZero(0), which is
|
||||
// undefined.
|
||||
uint32_t log2value = log2_floor_uint64(value | 0x1);
|
||||
return static_cast<size_t>((log2value * 9 + 73) / 64);
|
||||
}
|
||||
|
||||
template <typename U>
|
||||
constexpr IGUANA_INLINE size_t variant_intergal_size(U value) {
|
||||
using T = std::remove_reference_t<U>;
|
||||
if constexpr (sizeof(T) == 8) {
|
||||
return variant_uint64_size(static_cast<uint64_t>(value));
|
||||
}
|
||||
else if constexpr (sizeof(T) <= 4) {
|
||||
if constexpr (std::is_signed_v<T>) {
|
||||
if (value < 0) {
|
||||
return 10;
|
||||
}
|
||||
}
|
||||
return variant_uint32_size(static_cast<uint32_t>(value));
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "intergal in not supported");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename F, size_t... I>
|
||||
IGUANA_INLINE constexpr void for_each_n(F&& f, std::index_sequence<I...>) {
|
||||
(std::forward<F>(f)(std::integral_constant<size_t, I>{}), ...);
|
||||
}
|
||||
|
||||
template <size_t key_size, bool omit_default_val, typename Type>
|
||||
IGUANA_INLINE size_t str_numeric_size(Type&& t) {
|
||||
using T = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
if constexpr (std::is_same_v<T, std::string> ||
|
||||
std::is_same_v<T, std::string_view>) {
|
||||
// string
|
||||
if constexpr (omit_default_val) {
|
||||
if (t.size() == 0)
|
||||
IGUANA_UNLIKELY { return 0; }
|
||||
}
|
||||
if constexpr (key_size == 0) {
|
||||
return t.size();
|
||||
}
|
||||
else {
|
||||
return key_size + variant_uint32_size(static_cast<uint32_t>(t.size())) +
|
||||
t.size();
|
||||
}
|
||||
}
|
||||
else {
|
||||
// numeric
|
||||
if constexpr (omit_default_val) {
|
||||
if constexpr (is_fixed_v<T> || is_signed_varint_v<T>) {
|
||||
if (t.val == 0)
|
||||
IGUANA_UNLIKELY { return 0; }
|
||||
}
|
||||
else {
|
||||
if (t == static_cast<T>(0))
|
||||
IGUANA_UNLIKELY { return 0; }
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
if constexpr (std::is_same_v<bool, T>) {
|
||||
return 1 + key_size;
|
||||
}
|
||||
else {
|
||||
return key_size + variant_intergal_size(t);
|
||||
}
|
||||
}
|
||||
else if constexpr (detail::is_signed_varint_v<T>) {
|
||||
return key_size + variant_intergal_size(encode_zigzag(t.val));
|
||||
}
|
||||
else if constexpr (detail::is_fixed_v<T>) {
|
||||
return key_size + sizeof(typename T::value_type);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double> || std::is_same_v<T, float>) {
|
||||
return key_size + sizeof(T);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>) {
|
||||
using U = std::underlying_type_t<T>;
|
||||
return key_size + variant_intergal_size(static_cast<U>(t));
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "err");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t key_size, bool omit_default_val = true, typename Type,
|
||||
typename Arr>
|
||||
IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr);
|
||||
|
||||
template <typename Variant, typename T, size_t I>
|
||||
constexpr inline size_t get_variant_index() {
|
||||
if constexpr (I == 0) {
|
||||
static_assert(std::is_same_v<std::variant_alternative_t<0, Variant>, T>,
|
||||
"Type T is not found in Variant");
|
||||
return 0;
|
||||
}
|
||||
else if constexpr (std::is_same_v<std::variant_alternative_t<I, Variant>,
|
||||
T>) {
|
||||
return I;
|
||||
}
|
||||
else {
|
||||
return get_variant_index<Variant, T, I - 1>();
|
||||
}
|
||||
}
|
||||
|
||||
template <size_t field_no, typename Type, typename Arr>
|
||||
IGUANA_INLINE size_t pb_oneof_size(Type&& t, Arr& size_arr) {
|
||||
using T = std::decay_t<Type>;
|
||||
int len = 0;
|
||||
std::visit(
|
||||
[&len, &size_arr](auto&& value) IGUANA__INLINE_LAMBDA {
|
||||
using value_type =
|
||||
std::remove_const_t<std::remove_reference_t<decltype(value)>>;
|
||||
constexpr auto offset =
|
||||
get_variant_index<T, value_type, std::variant_size_v<T> - 1>();
|
||||
constexpr uint32_t key =
|
||||
((field_no + offset) << 3) |
|
||||
static_cast<uint32_t>(get_wire_type<value_type>());
|
||||
len = pb_key_value_size<variant_uint32_size_constexpr(key), false>(
|
||||
std::forward<value_type>(value), size_arr);
|
||||
},
|
||||
std::forward<Type>(t));
|
||||
return len;
|
||||
}
|
||||
|
||||
// returns size = key_size + optional(len_size) + len
|
||||
// when key_size == 0, return len
|
||||
template <size_t key_size, bool omit_default_val, typename Type, typename Arr>
|
||||
IGUANA_INLINE size_t pb_key_value_size(Type&& t, Arr& size_arr) {
|
||||
using T = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
|
||||
size_t len = 0;
|
||||
static constexpr auto tuple = get_members_tuple<T>();
|
||||
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
|
||||
size_t pre_index = -1;
|
||||
if constexpr (!inherits_from_base_v<T> && key_size != 0) {
|
||||
pre_index = size_arr.size();
|
||||
size_arr.push_back(0); // placeholder
|
||||
}
|
||||
for_each_n(
|
||||
[&len, &t, &size_arr](auto i) IGUANA__INLINE_LAMBDA {
|
||||
using field_type =
|
||||
std::tuple_element_t<decltype(i)::value,
|
||||
std::decay_t<decltype(tuple)>>;
|
||||
constexpr auto value = std::get<decltype(i)::value>(tuple);
|
||||
using U = typename field_type::value_type;
|
||||
auto& val = value.value(t);
|
||||
if constexpr (variant_v<U>) {
|
||||
constexpr auto offset =
|
||||
get_variant_index<U, typename field_type::sub_type,
|
||||
std::variant_size_v<U> - 1>();
|
||||
if constexpr (offset == 0) {
|
||||
len += pb_oneof_size<value.field_no>(val, size_arr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
constexpr uint32_t sub_key =
|
||||
(value.field_no << 3) |
|
||||
static_cast<uint32_t>(get_wire_type<U>());
|
||||
constexpr auto sub_keysize = variant_uint32_size_constexpr(sub_key);
|
||||
len += pb_key_value_size<sub_keysize>(val, size_arr);
|
||||
}
|
||||
},
|
||||
std::make_index_sequence<SIZE>{});
|
||||
if constexpr (inherits_from_base_v<T>) {
|
||||
t.cache_size = len;
|
||||
}
|
||||
else if constexpr (key_size != 0) {
|
||||
size_arr[pre_index] = len;
|
||||
}
|
||||
if constexpr (key_size == 0) {
|
||||
// for top level
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
if (len == 0) {
|
||||
// equals key_size + variant_uint32_size(len)
|
||||
return key_size + 1;
|
||||
}
|
||||
else {
|
||||
return key_size + variant_uint32_size(static_cast<uint32_t>(len)) + len;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (is_sequence_container<T>::value) {
|
||||
using item_type = typename T::value_type;
|
||||
size_t len = 0;
|
||||
if constexpr (is_lenprefix_v<item_type>) {
|
||||
for (auto& item : t) {
|
||||
len += pb_key_value_size<key_size, false>(item, size_arr);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
for (auto& item : t) {
|
||||
// here 0 to get pakced size, and item must be numeric
|
||||
len += str_numeric_size<0, false>(item);
|
||||
}
|
||||
if (len == 0) {
|
||||
return 0;
|
||||
}
|
||||
else {
|
||||
return key_size + variant_uint32_size(static_cast<uint32_t>(len)) + len;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (is_map_container<T>::value) {
|
||||
size_t len = 0;
|
||||
for (auto& [k, v] : t) {
|
||||
// the key_size of k and v is constant 1
|
||||
auto kv_len = pb_key_value_size<1, false>(k, size_arr) +
|
||||
pb_key_value_size<1, false>(v, size_arr);
|
||||
len += key_size + variant_uint32_size(static_cast<uint32_t>(kv_len)) +
|
||||
kv_len;
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else if constexpr (optional_v<T>) {
|
||||
if (!t.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
return pb_key_value_size<key_size, omit_default_val>(*t, size_arr);
|
||||
}
|
||||
else {
|
||||
return str_numeric_size<key_size, omit_default_val>(t);
|
||||
}
|
||||
}
|
||||
|
||||
// return the payload size
|
||||
template <bool skip_next = true, typename Type>
|
||||
IGUANA_INLINE size_t pb_value_size(Type&& t, uint32_t*& sz_ptr) {
|
||||
using T = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
|
||||
if constexpr (inherits_from_base_v<T>) {
|
||||
return t.cache_size;
|
||||
}
|
||||
else {
|
||||
// *sz_ptr is secure and logically guaranteed
|
||||
if constexpr (skip_next) {
|
||||
return *(sz_ptr++);
|
||||
}
|
||||
else {
|
||||
return *sz_ptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (is_sequence_container<T>::value) {
|
||||
using item_type = typename T::value_type;
|
||||
size_t len = 0;
|
||||
if constexpr (!is_lenprefix_v<item_type>) {
|
||||
for (auto& item : t) {
|
||||
len += str_numeric_size<0, false>(item);
|
||||
}
|
||||
return len;
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(item_type), "the size of this type is meaningless");
|
||||
}
|
||||
}
|
||||
else if constexpr (is_map_container<T>::value) {
|
||||
static_assert(!sizeof(T), "the size of this type is meaningless");
|
||||
}
|
||||
else if constexpr (optional_v<T>) {
|
||||
if (!t.has_value()) {
|
||||
return 0;
|
||||
}
|
||||
return pb_value_size(*t, sz_ptr);
|
||||
}
|
||||
else {
|
||||
return str_numeric_size<0, false>(t);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
} // namespace iguana
|
||||
|
|
@ -0,0 +1,219 @@
|
|||
#pragma once
|
||||
#include "detail/string_resize.hpp"
|
||||
#include "pb_util.hpp"
|
||||
|
||||
namespace iguana {
|
||||
namespace detail {
|
||||
|
||||
template <uint32_t key, typename V, typename It>
|
||||
IGUANA_INLINE void encode_varint_field(V val, It&& it) {
|
||||
static_assert(std::is_integral_v<V>, "must be integral");
|
||||
if constexpr (key != 0) {
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
}
|
||||
serialize_varint(val, it);
|
||||
}
|
||||
|
||||
template <uint32_t key, typename V, typename It>
|
||||
IGUANA_INLINE void encode_fixed_field(V val, It&& it) {
|
||||
if constexpr (key != 0) {
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
}
|
||||
constexpr size_t size = sizeof(V);
|
||||
// TODO: check Stream continuous
|
||||
memcpy(it, &val, size);
|
||||
it += size;
|
||||
}
|
||||
|
||||
template <uint32_t key, bool omit_default_val = true, typename Type,
|
||||
typename It>
|
||||
IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr);
|
||||
|
||||
template <uint32_t key, typename V, typename It>
|
||||
IGUANA_INLINE void encode_pair_value(V&& val, It&& it, size_t size,
|
||||
uint32_t*& sz_ptr) {
|
||||
if (size == 0)
|
||||
IGUANA_UNLIKELY {
|
||||
// map keys can't be omitted even if values are empty
|
||||
// TODO: repeated ?
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
serialize_varint(0, it);
|
||||
}
|
||||
else {
|
||||
to_pb_impl<key, false>(val, it, sz_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t key, bool omit_default_val, typename T, typename It>
|
||||
IGUANA_INLINE void encode_numeric_field(T t, It&& it) {
|
||||
if constexpr (omit_default_val) {
|
||||
if constexpr (is_fixed_v<T> || is_signed_varint_v<T>) {
|
||||
if (t.val == 0) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (t == static_cast<T>(0))
|
||||
IGUANA_UNLIKELY { return; }
|
||||
}
|
||||
}
|
||||
if constexpr (std::is_integral_v<T>) {
|
||||
detail::encode_varint_field<key>(t, it);
|
||||
}
|
||||
else if constexpr (detail::is_signed_varint_v<T>) {
|
||||
detail::encode_varint_field<key>(encode_zigzag(t.val), it);
|
||||
}
|
||||
else if constexpr (detail::is_fixed_v<T>) {
|
||||
detail::encode_fixed_field<key>(t.val, it);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, double> || std::is_same_v<T, float>) {
|
||||
detail::encode_fixed_field<key>(t, it);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>) {
|
||||
using U = std::underlying_type_t<T>;
|
||||
detail::encode_varint_field<key>(static_cast<U>(t), it);
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "unsupported type");
|
||||
}
|
||||
}
|
||||
|
||||
template <uint32_t field_no, typename Type, typename It>
|
||||
IGUANA_INLINE void to_pb_oneof(Type&& t, It&& it, uint32_t*& sz_ptr) {
|
||||
using T = std::decay_t<Type>;
|
||||
std::visit(
|
||||
[&it, &sz_ptr](auto&& value) IGUANA__INLINE_LAMBDA {
|
||||
using value_type =
|
||||
std::remove_const_t<std::remove_reference_t<decltype(value)>>;
|
||||
constexpr auto offset =
|
||||
get_variant_index<T, value_type, std::variant_size_v<T> - 1>();
|
||||
constexpr uint32_t key =
|
||||
((field_no + offset) << 3) |
|
||||
static_cast<uint32_t>(get_wire_type<value_type>());
|
||||
to_pb_impl<key, false>(std::forward<value_type>(value), it, sz_ptr);
|
||||
},
|
||||
std::forward<Type>(t));
|
||||
}
|
||||
|
||||
// omit_default_val = true indicates to omit the default value in searlization
|
||||
template <uint32_t key, bool omit_default_val, typename Type, typename It>
|
||||
IGUANA_INLINE void to_pb_impl(Type&& t, It&& it, uint32_t*& sz_ptr) {
|
||||
using T = std::remove_const_t<std::remove_reference_t<Type>>;
|
||||
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
|
||||
// can't be omitted even if values are empty
|
||||
if constexpr (key != 0) {
|
||||
auto len = pb_value_size(t, sz_ptr);
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
serialize_varint(len, it);
|
||||
if (len == 0)
|
||||
IGUANA_UNLIKELY { return; }
|
||||
}
|
||||
static constexpr auto tuple = get_members_tuple<T>();
|
||||
constexpr size_t SIZE = std::tuple_size_v<std::decay_t<decltype(tuple)>>;
|
||||
for_each_n(
|
||||
[&t, &it, &sz_ptr](auto i) IGUANA__INLINE_LAMBDA {
|
||||
using field_type =
|
||||
std::tuple_element_t<decltype(i)::value,
|
||||
std::decay_t<decltype(tuple)>>;
|
||||
constexpr auto value = std::get<decltype(i)::value>(tuple);
|
||||
auto& val = value.value(t);
|
||||
|
||||
using U = typename field_type::value_type;
|
||||
if constexpr (variant_v<U>) {
|
||||
constexpr auto offset =
|
||||
get_variant_index<U, typename field_type::sub_type,
|
||||
std::variant_size_v<U> - 1>();
|
||||
if constexpr (offset == 0) {
|
||||
to_pb_oneof<value.field_no>(val, it, sz_ptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
constexpr uint32_t sub_key =
|
||||
(value.field_no << 3) |
|
||||
static_cast<uint32_t>(get_wire_type<U>());
|
||||
to_pb_impl<sub_key>(val, it, sz_ptr);
|
||||
}
|
||||
},
|
||||
std::make_index_sequence<SIZE>{});
|
||||
}
|
||||
else if constexpr (is_sequence_container<T>::value) {
|
||||
// TODO support std::array
|
||||
// repeated values can't be omitted even if values are empty
|
||||
using item_type = typename T::value_type;
|
||||
if constexpr (is_lenprefix_v<item_type>) {
|
||||
// non-packed
|
||||
for (auto& item : t) {
|
||||
to_pb_impl<key, false>(item, it, sz_ptr);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (t.empty())
|
||||
IGUANA_UNLIKELY { return; }
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
serialize_varint(pb_value_size(t, sz_ptr), it);
|
||||
for (auto& item : t) {
|
||||
encode_numeric_field<false, 0>(item, it);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if constexpr (is_map_container<T>::value) {
|
||||
using first_type = typename T::key_type;
|
||||
using second_type = typename T::mapped_type;
|
||||
constexpr uint32_t key1 =
|
||||
(1 << 3) | static_cast<uint32_t>(get_wire_type<first_type>());
|
||||
constexpr auto key1_size = variant_uint32_size_constexpr(key1);
|
||||
constexpr uint32_t key2 =
|
||||
(2 << 3) | static_cast<uint32_t>(get_wire_type<second_type>());
|
||||
constexpr auto key2_size = variant_uint32_size_constexpr(key2);
|
||||
|
||||
for (auto& [k, v] : t) {
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
// k must be string or numeric
|
||||
auto k_val_len = str_numeric_size<0, false>(k);
|
||||
auto v_val_len = pb_value_size<false>(v, sz_ptr);
|
||||
auto pair_len = key1_size + key2_size + k_val_len + v_val_len;
|
||||
if constexpr (is_lenprefix_v<first_type>) {
|
||||
pair_len += variant_uint32_size(k_val_len);
|
||||
}
|
||||
if constexpr (is_lenprefix_v<second_type>) {
|
||||
pair_len += variant_uint32_size(v_val_len);
|
||||
}
|
||||
serialize_varint(pair_len, it);
|
||||
// map k and v can't be omitted even if values are empty
|
||||
encode_pair_value<key1>(k, it, k_val_len, sz_ptr);
|
||||
encode_pair_value<key2>(v, it, v_val_len, sz_ptr);
|
||||
}
|
||||
}
|
||||
else if constexpr (optional_v<T>) {
|
||||
if (!t.has_value()) {
|
||||
return;
|
||||
}
|
||||
to_pb_impl<key, omit_default_val>(*t, it, sz_ptr);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string> ||
|
||||
std::is_same_v<T, std::string_view>) {
|
||||
if constexpr (omit_default_val) {
|
||||
if (t.size() == 0)
|
||||
IGUANA_UNLIKELY { return; }
|
||||
}
|
||||
serialize_varint_u32_constexpr<key>(it);
|
||||
serialize_varint(t.size(), it);
|
||||
memcpy(it, t.data(), t.size());
|
||||
it += t.size();
|
||||
}
|
||||
else {
|
||||
encode_numeric_field<key, omit_default_val>(t, it);
|
||||
}
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
template <typename T, typename Stream>
|
||||
IGUANA_INLINE void to_pb(T& t, Stream& out) {
|
||||
std::vector<uint32_t> size_arr;
|
||||
auto byte_len = detail::pb_key_value_size<0>(t, size_arr);
|
||||
detail::resize(out, byte_len);
|
||||
auto sz_ptr = size_arr.empty() ? nullptr : &size_arr[0];
|
||||
detail::to_pb_impl<0>(t, &out[0], sz_ptr);
|
||||
}
|
||||
|
||||
} // namespace iguana
|
||||
|
|
@ -9,6 +9,7 @@
|
|||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
|
@ -19,6 +20,7 @@
|
|||
|
||||
#include "detail/string_stream.hpp"
|
||||
#include "detail/traits.hpp"
|
||||
#include "enum_reflection.hpp"
|
||||
#include "frozen/string.h"
|
||||
#include "frozen/unordered_map.h"
|
||||
|
||||
|
|
@ -550,9 +552,88 @@ namespace iguana::detail {
|
|||
#define MAKE_STR_LIST(...) \
|
||||
MACRO_CONCAT(CON_STR, GET_ARG_COUNT(__VA_ARGS__))(__VA_ARGS__)
|
||||
|
||||
template <typename T>
|
||||
struct identity {};
|
||||
|
||||
struct field_info {
|
||||
size_t offset;
|
||||
std::string_view type_name;
|
||||
};
|
||||
|
||||
struct base {
|
||||
virtual void to_pb(std::string &str) {}
|
||||
virtual void from_pb(std::string_view str) {}
|
||||
virtual std::vector<std::string_view> get_fields_name() { return {}; }
|
||||
virtual iguana::detail::field_info get_field_info(std::string_view name) {
|
||||
return {};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &get_field_value(std::string_view name) {
|
||||
auto info = get_field_info(name);
|
||||
check_field<T>(name, info);
|
||||
auto ptr = (((char *)this) + info.offset);
|
||||
return *((T *)ptr);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void set_field_value(std::string_view name, T val) {
|
||||
auto info = get_field_info(name);
|
||||
check_field<T>(name, info);
|
||||
|
||||
auto ptr = (((char *)this) + info.offset);
|
||||
|
||||
*((T *)ptr) = std::move(val);
|
||||
}
|
||||
virtual ~base() {}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void check_field(std::string_view name, const field_info &info) {
|
||||
if (info.offset == 0) {
|
||||
throw std::invalid_argument(std::string(name) + " field not exist ");
|
||||
}
|
||||
|
||||
#if defined(__clang__) || defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && __GNUC__ > 8)
|
||||
if (info.type_name != iguana::type_string<T>()) {
|
||||
std::string str = "type is not match: can not assign ";
|
||||
str.append(iguana::type_string<T>());
|
||||
str.append(" to ").append(info.type_name);
|
||||
|
||||
throw std::invalid_argument(str);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
};
|
||||
|
||||
inline std::unordered_map<std::string_view,
|
||||
std::function<std::shared_ptr<base>()>>
|
||||
g_pb_map;
|
||||
|
||||
template <typename T>
|
||||
inline bool register_type() {
|
||||
#if defined(__clang__) || defined(_MSC_VER) || \
|
||||
(defined(__GNUC__) && __GNUC__ > 8)
|
||||
if constexpr (std::is_base_of_v<base, T>) {
|
||||
auto it = g_pb_map.emplace(type_string<T>(), [] {
|
||||
return std::make_shared<T>();
|
||||
});
|
||||
return it.second;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
#else
|
||||
return true;
|
||||
#endif
|
||||
}
|
||||
|
||||
#define MAKE_META_DATA_IMPL(STRUCT_NAME, ...) \
|
||||
static inline bool IGUANA_UNIQUE_VARIABLE(reg_var) = \
|
||||
iguana::detail::register_type<STRUCT_NAME>(); \
|
||||
[[maybe_unused]] inline static auto iguana_reflect_members( \
|
||||
STRUCT_NAME const &) { \
|
||||
const iguana::detail::identity<STRUCT_NAME> &) { \
|
||||
struct reflect_members { \
|
||||
constexpr decltype(auto) static apply_impl() { \
|
||||
return std::make_tuple(__VA_ARGS__); \
|
||||
|
|
@ -602,7 +683,7 @@ constexpr std::array<frozen::string, N> get_alias_arr(Args... pairs) {
|
|||
|
||||
#define MAKE_META_DATA_IMPL_ALIAS(STRUCT_NAME, ALIAS, ...) \
|
||||
[[maybe_unused]] inline static auto iguana_reflect_members( \
|
||||
STRUCT_NAME const &) { \
|
||||
const iguana::detail::identity<STRUCT_NAME> &) { \
|
||||
struct reflect_members { \
|
||||
constexpr decltype(auto) static apply_impl() { \
|
||||
return iguana::detail::get_mem_ptr_tp(__VA_ARGS__); \
|
||||
|
|
@ -622,7 +703,8 @@ constexpr std::array<frozen::string, N> get_alias_arr(Args... pairs) {
|
|||
}
|
||||
|
||||
#define MAKE_META_DATA_IMPL_EMPTY(STRUCT_NAME) \
|
||||
inline auto iguana_reflect_members(STRUCT_NAME const &) { \
|
||||
inline auto iguana_reflect_members( \
|
||||
const iguana::detail::identity<STRUCT_NAME> &) { \
|
||||
struct reflect_members { \
|
||||
constexpr decltype(auto) static apply_impl() { \
|
||||
return std::make_tuple(); \
|
||||
|
|
@ -692,6 +774,143 @@ inline constexpr auto get_iguana_struct_map() {
|
|||
}
|
||||
}
|
||||
|
||||
template <typename T,
|
||||
typename ElementType = typename member_traits<T>::value_type>
|
||||
struct field_t {
|
||||
using member_type = T;
|
||||
using owner_type = typename member_traits<T>::owner_type;
|
||||
using value_type = typename member_traits<T>::value_type;
|
||||
using sub_type = ElementType;
|
||||
constexpr field_t() = default;
|
||||
constexpr field_t(T member, uint32_t number, frozen::string name = "")
|
||||
: member_ptr(member), field_name(name), field_no(number) {}
|
||||
|
||||
T member_ptr;
|
||||
frozen::string field_name;
|
||||
uint32_t field_no;
|
||||
|
||||
auto &value(owner_type &value) const { return value.*member_ptr; }
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct field_type_t;
|
||||
|
||||
template <typename... Args>
|
||||
struct field_type_t<std::tuple<Args...>> {
|
||||
using value_type = std::variant<Args...>;
|
||||
};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_custom_reflection : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_custom_reflection<
|
||||
T, std::void_t<decltype(get_members_impl(std::declval<T *>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_reflection : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_reflection_v = is_reflection<T>::value;
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_custom_reflection_v = is_custom_reflection<T>::value;
|
||||
|
||||
template <typename T, typename S, size_t... I>
|
||||
constexpr inline auto build_variant_fields(T t, S &s, uint32_t base_idx,
|
||||
std::index_sequence<I...>) {
|
||||
using value_type = typename member_traits<T>::value_type;
|
||||
return std::tuple(field_t<T, std::variant_alternative_t<I, value_type>>{
|
||||
t, (base_idx + uint32_t(I)), s}...);
|
||||
}
|
||||
|
||||
template <uint32_t I, typename T, typename S>
|
||||
constexpr inline auto build_fields(T t, S &s, uint32_t &index) {
|
||||
using value_type = typename member_traits<T>::value_type;
|
||||
if constexpr (is_variant<value_type>::value) {
|
||||
constexpr uint32_t Size = std::variant_size_v<value_type>;
|
||||
index += (Size - 1);
|
||||
return build_variant_fields(t, s, I + 1, std::make_index_sequence<Size>{});
|
||||
}
|
||||
else {
|
||||
uint32_t field_no = (I == index) ? (I + 1) : (I + index);
|
||||
index++;
|
||||
return std::tuple(field_t{t, field_no, s});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename U, size_t... I>
|
||||
constexpr inline auto get_members_tuple_impl(T &&tp, U &&arr,
|
||||
std::index_sequence<I...> &&) {
|
||||
uint32_t index = 0;
|
||||
return std::tuple_cat(build_fields<I>(std::get<I>(tp), arr[I], index)...);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline auto get_members_tuple() {
|
||||
if constexpr (is_reflection<T>::value) {
|
||||
using reflect_members = decltype(iguana_reflect_type(std::declval<T>()));
|
||||
using Tuple = decltype(reflect_members::apply_impl());
|
||||
constexpr size_t Size = std::tuple_size_v<Tuple>;
|
||||
return get_members_tuple_impl(reflect_members::apply_impl(),
|
||||
reflect_members::arr(),
|
||||
std::make_index_sequence<Size>{});
|
||||
}
|
||||
else if constexpr (is_custom_reflection_v<T>) {
|
||||
using U = std::remove_const_t<std::remove_reference_t<T>>;
|
||||
return get_members_impl((U *)nullptr);
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "expected reflection or custom reflection");
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t Size, typename Tuple, size_t... I>
|
||||
constexpr auto inline get_members_impl(Tuple &&tp, std::index_sequence<I...>) {
|
||||
return frozen::unordered_map<uint32_t, T, sizeof...(I)>{
|
||||
{std::get<I>(tp).field_no,
|
||||
T{std::in_place_index<I>, std::move(std::get<I>(tp))}}...};
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr size_t count_variant_size() {
|
||||
if constexpr (is_variant<T>::value) {
|
||||
return std::variant_size_v<T>;
|
||||
}
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, size_t... I>
|
||||
constexpr size_t tuple_type_count_impl(std::index_sequence<I...>) {
|
||||
return (
|
||||
(count_variant_size<member_value_type_t<std::tuple_element_t<I, T>>>() +
|
||||
...));
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr size_t tuple_type_count() {
|
||||
return tuple_type_count_impl<T>(
|
||||
std::make_index_sequence<std::tuple_size_v<T>>{});
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
constexpr inline auto get_members() {
|
||||
if constexpr (is_reflection_v<T> || is_custom_reflection_v<T>) {
|
||||
constexpr auto tp = get_members_tuple<T>();
|
||||
using Tuple = std::decay_t<decltype(tp)>;
|
||||
using value_type = typename field_type_t<Tuple>::value_type;
|
||||
constexpr auto Size = tuple_type_count<Tuple>();
|
||||
return get_members_impl<value_type, Size>(tp,
|
||||
std::make_index_sequence<Size>{});
|
||||
}
|
||||
else {
|
||||
static_assert(!sizeof(T), "expected reflection or custom reflection");
|
||||
}
|
||||
}
|
||||
|
||||
#define REFLECTION(STRUCT_NAME, ...) \
|
||||
MAKE_META_DATA(STRUCT_NAME, #STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), \
|
||||
__VA_ARGS__)
|
||||
|
|
@ -703,11 +922,7 @@ inline constexpr auto get_iguana_struct_map() {
|
|||
STRUCT_NAME, ALIAS, \
|
||||
std::tuple_size_v<decltype(std::make_tuple(__VA_ARGS__))>, __VA_ARGS__)
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__)
|
||||
#else
|
||||
#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__)
|
||||
#endif
|
||||
template <typename T>
|
||||
struct iguana_required_struct;
|
||||
#define REQUIRED_IMPL(STRUCT_NAME, N, ...) \
|
||||
|
|
@ -762,12 +977,6 @@ inline int add_custom_fields(std::string_view key,
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __COUNTER__)
|
||||
#else
|
||||
#define IGUANA_UNIQUE_VARIABLE(str) MACRO_CONCAT(str, __LINE__)
|
||||
#endif
|
||||
|
||||
#define CUSTOM_FIELDS_IMPL(STRUCT_NAME, N, ...) \
|
||||
inline auto IGUANA_UNIQUE_VARIABLE(STRUCT_NAME) = iguana::add_custom_fields( \
|
||||
#STRUCT_NAME, {MARCO_EXPAND(MACRO_CONCAT(CON_STR, N)(__VA_ARGS__))});
|
||||
|
|
@ -776,14 +985,16 @@ inline int add_custom_fields(std::string_view key,
|
|||
CUSTOM_FIELDS_IMPL(STRUCT_NAME, GET_ARG_COUNT(__VA_ARGS__), __VA_ARGS__)
|
||||
|
||||
template <typename T>
|
||||
using Reflect_members = decltype(iguana_reflect_members(std::declval<T>()));
|
||||
using Reflect_members = decltype(iguana_reflect_members(
|
||||
std::declval<iguana::detail::identity<T>>()));
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_public_reflection : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_public_reflection<
|
||||
T, std::void_t<decltype(iguana_reflect_members(std::declval<T>()))>>
|
||||
struct is_public_reflection<T,
|
||||
std::void_t<decltype(iguana_reflect_members(
|
||||
std::declval<iguana::detail::identity<T>>()))>>
|
||||
: std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
|
|
@ -795,14 +1006,11 @@ struct is_private_reflection : std::false_type {};
|
|||
template <typename T>
|
||||
struct is_private_reflection<
|
||||
T, std::void_t<decltype(std::declval<T>().iguana_reflect_members(
|
||||
std::declval<T>()))>> : std::true_type {};
|
||||
std::declval<iguana::detail::identity<T>>()))>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr bool is_private_reflection_v = is_private_reflection<T>::value;
|
||||
|
||||
template <typename T, typename = void>
|
||||
struct is_reflection : std::false_type {};
|
||||
|
||||
template <typename T>
|
||||
struct is_reflection<T, std::enable_if_t<is_private_reflection_v<T>>>
|
||||
: std::true_type {};
|
||||
|
|
@ -813,17 +1021,14 @@ struct is_reflection<T, std::enable_if_t<is_public_reflection_v<T>>>
|
|||
|
||||
template <typename T>
|
||||
inline auto iguana_reflect_type(const T &t) {
|
||||
if constexpr (is_public_reflection_v<T>) {
|
||||
return iguana_reflect_members(t);
|
||||
if constexpr (is_public_reflection_v<std::decay_t<T>>) {
|
||||
return iguana_reflect_members(iguana::detail::identity<T>{});
|
||||
}
|
||||
else {
|
||||
return t.iguana_reflect_members(t);
|
||||
return t.iguana_reflect_members(iguana::detail::identity<T>{});
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
inline constexpr bool is_reflection_v = is_reflection<T>::value;
|
||||
|
||||
template <std::size_t index, template <typename...> typename Condition,
|
||||
typename Tuple, typename Owner>
|
||||
constexpr int element_index_helper() {
|
||||
|
|
@ -1112,7 +1317,8 @@ constexpr void for_each(const std::tuple<Args...> &t, F &&f,
|
|||
}
|
||||
|
||||
template <typename T, typename F>
|
||||
constexpr std::enable_if_t<is_reflection<T>::value> for_each(T &&t, F &&f) {
|
||||
constexpr std::enable_if_t<is_reflection<std::decay_t<T>>::value> for_each(
|
||||
T &&t, F &&f) {
|
||||
using M = decltype(iguana_reflect_type(std::forward<T>(t)));
|
||||
for_each(M::apply_impl(), std::forward<F>(f),
|
||||
std::make_index_sequence<M::value()>{});
|
||||
|
|
|
|||
|
|
@ -130,12 +130,6 @@ constexpr inline bool shared_ptr_v =
|
|||
template <typename T>
|
||||
constexpr inline bool smart_ptr_v = shared_ptr_v<T> || unique_ptr_v<T>;
|
||||
|
||||
template <typename T>
|
||||
struct is_variant : std::false_type {};
|
||||
|
||||
template <typename... T>
|
||||
struct is_variant<std::variant<T...>> : std::true_type {};
|
||||
|
||||
template <typename T>
|
||||
constexpr inline bool variant_v = is_variant<std::remove_cvref_t<T>>::value;
|
||||
|
||||
|
|
|
|||
|
|
@ -5,4 +5,4 @@
|
|||
// IGUANA_VERSION % 100 is the sub-minor version
|
||||
// IGUANA_VERSION / 100 % 1000 is the minor version
|
||||
// IGUANA_VERSION / 100000 is the major version
|
||||
#define IGUANA_VERSION 100004 // 1.0.4
|
||||
#define IGUANA_VERSION 100005 // 1.0.5
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
||||
* Copyright (c) 2024, Alibaba Group Holding Limited;
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -14,89 +14,4 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <vector>
|
||||
#if defined __clang__
|
||||
#define STRUCT_PB_INLINE __attribute__((always_inline)) inline
|
||||
#elif defined _MSC_VER
|
||||
#define STRUCT_PB_INLINE __forceinline
|
||||
#else
|
||||
#define STRUCT_PB_INLINE __attribute__((always_inline)) inline
|
||||
#endif
|
||||
#define STRUCT_PB_NODISCARD [[nodiscard]]
|
||||
namespace struct_pb {
|
||||
|
||||
struct UnknownFields {
|
||||
STRUCT_PB_NODISCARD std::size_t total_size() const {
|
||||
std::size_t total = 0;
|
||||
for (const auto& f : fields) {
|
||||
total += f.len;
|
||||
}
|
||||
return total;
|
||||
}
|
||||
void serialize_to(char* data, std::size_t& pos, std::size_t size) const {
|
||||
for (const auto& f : fields) {
|
||||
assert(pos + f.len <= size);
|
||||
std::memcpy(data + pos, f.data, f.len);
|
||||
pos += f.len;
|
||||
}
|
||||
}
|
||||
void add_field(const char* data, std::size_t start, std::size_t end) {
|
||||
fields.push_back(Field{data + start, end - start});
|
||||
}
|
||||
struct Field {
|
||||
const char* data;
|
||||
std::size_t len;
|
||||
};
|
||||
std::vector<Field> fields;
|
||||
};
|
||||
/*
|
||||
* Low-Level API for struct_pb user
|
||||
* the following internal API will be generated by struct_pb protoc plugin
|
||||
*/
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
STRUCT_PB_NODISCARD std::size_t get_needed_size(
|
||||
const T& t, const UnknownFields& unknown_fields = {});
|
||||
template <typename T>
|
||||
void serialize_to(char* data, std::size_t size, const T& t,
|
||||
const UnknownFields& unknown_fields = {});
|
||||
template <typename T>
|
||||
STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data,
|
||||
std::size_t size,
|
||||
UnknownFields& unknown_fields);
|
||||
template <typename T>
|
||||
STRUCT_PB_NODISCARD bool deserialize_to(T& t, const char* data,
|
||||
std::size_t size);
|
||||
} // namespace internal
|
||||
|
||||
/*
|
||||
* High-Level API for struct_pb user
|
||||
* If you need more fine-grained operations, encapsulate the internal API
|
||||
* yourself.
|
||||
*/
|
||||
template <typename Buffer = std::vector<char>, typename T>
|
||||
STRUCT_PB_NODISCARD Buffer serialize(const T& t,
|
||||
const UnknownFields& unknown_fields = {}) {
|
||||
Buffer buffer;
|
||||
auto size = struct_pb::internal::get_needed_size(t, unknown_fields);
|
||||
buffer.resize(size);
|
||||
struct_pb::internal::serialize_to(buffer.data(), buffer.size(), t,
|
||||
unknown_fields);
|
||||
return buffer;
|
||||
}
|
||||
template <typename T, typename Buffer>
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to(
|
||||
T& t, UnknownFields& unknown_fields, const Buffer& buffer) {
|
||||
return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size(),
|
||||
unknown_fields);
|
||||
}
|
||||
template <typename T, typename Buffer>
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_to(T& t,
|
||||
const Buffer& buffer) {
|
||||
return struct_pb::internal::deserialize_to(t, buffer.data(), buffer.size());
|
||||
}
|
||||
|
||||
} // namespace struct_pb
|
||||
#include "struct_pb/struct_pb_impl.hpp"
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
||||
* Copyright (c) 2024, Alibaba Group Holding Limited;
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
|
|
@ -14,171 +14,6 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
#pragma once
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <map>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ylt/struct_pb.hpp"
|
||||
|
||||
namespace struct_pb {
|
||||
|
||||
namespace internal {
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint32_t encode_zigzag(int32_t v) {
|
||||
return (static_cast<uint32_t>(v) << 1U) ^
|
||||
static_cast<uint32_t>(
|
||||
-static_cast<int32_t>(static_cast<uint32_t>(v) >> 31U));
|
||||
}
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE uint64_t encode_zigzag(int64_t v) {
|
||||
return (static_cast<uint64_t>(v) << 1U) ^
|
||||
static_cast<uint64_t>(
|
||||
-static_cast<int64_t>(static_cast<uint64_t>(v) >> 63U));
|
||||
}
|
||||
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint64_t u) {
|
||||
return static_cast<int64_t>((u >> 1U)) ^
|
||||
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
|
||||
}
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE int64_t decode_zigzag(uint32_t u) {
|
||||
return static_cast<int64_t>((u >> 1U)) ^
|
||||
static_cast<uint64_t>(-static_cast<int64_t>(u & 1U));
|
||||
}
|
||||
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE std::size_t calculate_varint_size(
|
||||
uint64_t v) {
|
||||
std::size_t ret = 0;
|
||||
do {
|
||||
ret++;
|
||||
v >>= 7;
|
||||
} while (v != 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
[[nodiscard]] STRUCT_PB_INLINE bool decode_varint(const char* data,
|
||||
std::size_t& pos_,
|
||||
std::size_t size_,
|
||||
uint64_t& v) {
|
||||
// fix test failed on arm due to different char definition
|
||||
const signed char* data_ = reinterpret_cast<const signed char*>(data);
|
||||
// from https://github.com/facebook/folly/blob/main/folly/Varint.h
|
||||
if (pos_ < size_ && (static_cast<uint64_t>(data_[pos_]) & 0x80U) == 0) {
|
||||
v = static_cast<uint64_t>(data_[pos_]);
|
||||
pos_++;
|
||||
return true;
|
||||
}
|
||||
constexpr const int8_t max_varint_length = sizeof(uint64_t) * 8 / 7 + 1;
|
||||
uint64_t val = 0;
|
||||
if (size_ - pos_ >= max_varint_length) [[likely]] {
|
||||
do {
|
||||
// clang-format off
|
||||
int64_t b = data_[pos_++];
|
||||
val = ((uint64_t(b) & 0x7fU) ); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 7U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 14U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 21U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 28U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 35U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 42U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 49U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x7fU) << 56U); if (b >= 0) { break; }
|
||||
b = data_[pos_++]; val |= ((uint64_t(b) & 0x01U) << 63U); if (b >= 0) { break; }
|
||||
// clang-format on
|
||||
return false;
|
||||
} while (false);
|
||||
}
|
||||
else {
|
||||
unsigned int shift = 0;
|
||||
while (pos_ != size_ && int64_t(data_[pos_]) < 0) {
|
||||
val |= (uint64_t(data_[pos_++]) & 0x7fU) << shift;
|
||||
shift += 7;
|
||||
}
|
||||
if (pos_ == size_) {
|
||||
return false;
|
||||
}
|
||||
val |= uint64_t(data_[pos_++]) << shift;
|
||||
}
|
||||
v = val;
|
||||
return true;
|
||||
}
|
||||
STRUCT_PB_INLINE void serialize_varint(char* const data, std::size_t& pos,
|
||||
std::size_t size, uint64_t v) {
|
||||
while (v >= 0x80) {
|
||||
assert(pos < size);
|
||||
data[pos++] = static_cast<uint8_t>(v | 0x80);
|
||||
v >>= 7;
|
||||
}
|
||||
data[pos++] = static_cast<uint8_t>(v);
|
||||
}
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool deserialize_varint(const char* data,
|
||||
std::size_t& pos,
|
||||
std::size_t size,
|
||||
uint64_t& v) {
|
||||
return decode_varint(data, pos, size, v);
|
||||
}
|
||||
STRUCT_PB_NODISCARD STRUCT_PB_INLINE bool read_tag(const char* data,
|
||||
std::size_t& pos,
|
||||
std::size_t size,
|
||||
uint64_t& tag) {
|
||||
return deserialize_varint(data, pos, size, tag);
|
||||
}
|
||||
inline bool deserialize_unknown(const char* data, std::size_t& pos,
|
||||
std::size_t size, uint32_t tag,
|
||||
UnknownFields& unknown_fields) {
|
||||
uint32_t field_number = tag >> 3;
|
||||
if (field_number == 0) {
|
||||
return false;
|
||||
}
|
||||
auto offset = internal::calculate_varint_size(tag);
|
||||
auto start = pos - offset;
|
||||
uint32_t wire_type = tag & 0b0000'0111;
|
||||
switch (wire_type) {
|
||||
case 0: {
|
||||
uint64_t t;
|
||||
auto ok = internal::deserialize_varint(data, pos, size, t);
|
||||
if (!ok) [[unlikely]] {
|
||||
return false;
|
||||
}
|
||||
unknown_fields.add_field(data, start, pos);
|
||||
break;
|
||||
}
|
||||
case 1: {
|
||||
static_assert(sizeof(double) == 8);
|
||||
if (pos + 8 > size) [[unlikely]] {
|
||||
return false;
|
||||
}
|
||||
pos += 8;
|
||||
unknown_fields.add_field(data, start, pos);
|
||||
break;
|
||||
}
|
||||
case 2: {
|
||||
uint64_t sz;
|
||||
auto ok = internal::deserialize_varint(data, pos, size, sz);
|
||||
if (!ok) [[unlikely]] {
|
||||
return false;
|
||||
}
|
||||
if (pos + sz > size) [[unlikely]] {
|
||||
return false;
|
||||
}
|
||||
pos += sz;
|
||||
unknown_fields.add_field(data, start, pos);
|
||||
break;
|
||||
}
|
||||
case 5: {
|
||||
static_assert(sizeof(float) == 4);
|
||||
if (pos + 4 > size) [[unlikely]] {
|
||||
return false;
|
||||
}
|
||||
pos += 4;
|
||||
unknown_fields.add_field(data, start, pos);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
assert(false && "error path");
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
} // namespace struct_pb
|
||||
#include <iguana/pb_reader.hpp>
|
||||
#include <iguana/pb_writer.hpp>
|
||||
namespace struct_pb = iguana;
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ cc_binary(
|
|||
"no_op.cpp",
|
||||
"no_op.h",
|
||||
"sample.hpp",
|
||||
"struct_pb_sample.hpp",
|
||||
"struct_pack_sample.hpp",
|
||||
"msgpack_sample.hpp"
|
||||
],
|
||||
|
|
|
|||
|
|
@ -15,19 +15,6 @@ if (Protobuf_FOUND)
|
|||
target_link_libraries(struct_pack_benchmark PRIVATE protobuf::libprotobuf)
|
||||
|
||||
target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF)
|
||||
if (BUILD_STRUCT_PB)
|
||||
protobuf_generate_struct_pb(STRUCT_PACK_BENCHMARK_PROTO_SRCS2
|
||||
STRUCT_PACK_BENCHMARK_PROTO_HDRS2
|
||||
data_def.proto
|
||||
OPTION "namespace=struct_pb_sample"
|
||||
)
|
||||
target_sources(struct_pack_benchmark PRIVATE
|
||||
${STRUCT_PACK_BENCHMARK_PROTO_SRCS2}
|
||||
${STRUCT_PACK_BENCHMARK_PROTO_HDRS2}
|
||||
)
|
||||
target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_STRUCT_PB)
|
||||
endif()
|
||||
target_compile_definitions(struct_pack_benchmark PRIVATE HAVE_PROTOBUF)
|
||||
endif ()
|
||||
|
||||
target_compile_definitions(struct_pack_benchmark PRIVATE MSGPACK_NO_BOOST)
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
#include <map>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
|
||||
#define SEQUENTIAL_PARSE
|
||||
#include "struct_pack_sample.hpp"
|
||||
|
||||
#if __has_include(<msgpack.hpp>)
|
||||
|
|
@ -14,10 +14,8 @@
|
|||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "protobuf_sample.hpp"
|
||||
#ifdef HAVE_STRUCT_PB
|
||||
#endif
|
||||
#include "struct_pb_sample.hpp"
|
||||
#endif
|
||||
#endif
|
||||
#ifdef HAVE_FLATBUFFER
|
||||
#include "flatbuffer_sample.hpp"
|
||||
#endif
|
||||
|
|
@ -120,11 +118,9 @@ int main(int argc, char** argv) {
|
|||
map.emplace(LibType::MSGPACK, new message_pack_sample());
|
||||
#endif
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#ifdef HAVE_STRUCT_PB
|
||||
map.emplace(LibType::STRUCT_PB, new struct_pb_sample::struct_pb_sample_t());
|
||||
#endif
|
||||
map.emplace(LibType::PROTOBUF, new protobuf_sample_t());
|
||||
#endif
|
||||
map.emplace(LibType::STRUCT_PB, new struct_pb_sample());
|
||||
#ifdef HAVE_FLATBUFFER
|
||||
map.emplace(LibType::FLATBUFFER, new flatbuffer_sample_t());
|
||||
#endif
|
||||
|
|
@ -143,9 +139,7 @@ int main(int argc, char** argv) {
|
|||
|
||||
run_benchmark(map, LibType::STRUCT_PACK);
|
||||
|
||||
#ifdef HAVE_STRUCT_PB
|
||||
run_benchmark(map, LibType::STRUCT_PB);
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -211,8 +211,6 @@ struct protobuf_sample_t : public base_sample {
|
|||
buffer_.clear();
|
||||
sample.SerializeToString(&buffer_);
|
||||
|
||||
T obj;
|
||||
|
||||
uint64_t ns = 0;
|
||||
std::string bench_name =
|
||||
name() + " deserialize " + get_sample_name(sample_type);
|
||||
|
|
@ -220,6 +218,7 @@ struct protobuf_sample_t : public base_sample {
|
|||
{
|
||||
ScopedTimer timer(bench_name.data(), ns);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
T obj;
|
||||
obj.ParseFromString(buffer_);
|
||||
no_op((char *)&obj);
|
||||
no_op(buffer_);
|
||||
|
|
|
|||
|
|
@ -148,8 +148,6 @@ struct struct_pack_sample : public base_sample {
|
|||
buffer_.clear();
|
||||
struct_pack::serialize_to(buffer_, sample);
|
||||
|
||||
U obj;
|
||||
|
||||
uint64_t ns = 0;
|
||||
std::string bench_name =
|
||||
name() + " deserialize " + get_sample_name(sample_type);
|
||||
|
|
@ -157,6 +155,7 @@ struct struct_pack_sample : public base_sample {
|
|||
{
|
||||
ScopedTimer timer(bench_name.data(), ns);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
U obj;
|
||||
[[maybe_unused]] auto ec = struct_pack::deserialize_to(obj, buffer_);
|
||||
no_op((char *)&obj);
|
||||
no_op(buffer_);
|
||||
|
|
|
|||
|
|
@ -1,162 +1,208 @@
|
|||
#pragma once
|
||||
#include <cassert>
|
||||
#include <optional>
|
||||
#include <stdexcept>
|
||||
#include <valarray>
|
||||
#include <ylt/struct_pb.hpp>
|
||||
|
||||
#include "ScopedTimer.hpp"
|
||||
#include "no_op.h"
|
||||
#include "sample.hpp"
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "data_def.struct_pb.h"
|
||||
#endif
|
||||
namespace pb_sample {
|
||||
struct person : public iguana::base_impl<person> {
|
||||
person() = default;
|
||||
person(int32_t a, std::string b, int c, double d)
|
||||
: id(a), name(std::move(b)), age(c), salary(d) {}
|
||||
int32_t id;
|
||||
std::string name;
|
||||
int age;
|
||||
double salary;
|
||||
};
|
||||
REFLECTION(person, id, name, age, salary);
|
||||
|
||||
namespace struct_pb_sample {
|
||||
struct persons : public iguana::base_impl<persons> {
|
||||
persons() = default;
|
||||
explicit persons(std::vector<person> l) : list(std::move(l)) {}
|
||||
std::vector<person> list;
|
||||
};
|
||||
REFLECTION(persons, list);
|
||||
|
||||
inline auto create_rects(std::size_t object_count) {
|
||||
rect32s rcs;
|
||||
for (int i = 0; i < object_count; ++i) {
|
||||
rect32 rc{1, 0, 11, 1};
|
||||
rcs.rect32_list.emplace_back(rc);
|
||||
struct rect : public iguana::base_impl<rect> {
|
||||
rect() = default;
|
||||
rect(int32_t a, int32_t b, int32_t c, int32_t d)
|
||||
: x(a), y(b), width(c), height(d) {}
|
||||
int32_t x = 1;
|
||||
int32_t y = 0;
|
||||
int32_t width = 11;
|
||||
int32_t height = 1;
|
||||
};
|
||||
REFLECTION(rect, x, y, width, height);
|
||||
|
||||
struct rects : public iguana::base_impl<rects> {
|
||||
rects() = default;
|
||||
explicit rects(std::vector<rect> l) : list(std::move(l)) {}
|
||||
std::vector<rect> list;
|
||||
};
|
||||
REFLECTION(rects, list);
|
||||
|
||||
struct Vec3 : public iguana::base_impl<Vec3> {
|
||||
Vec3() = default;
|
||||
Vec3(float a, float b, float c) : x(a), y(b), z(c) {}
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
REFLECTION(Vec3, x, y, z);
|
||||
};
|
||||
|
||||
struct Weapon : public iguana::base_impl<Weapon> {
|
||||
Weapon() = default;
|
||||
Weapon(std::string s, int32_t d) : name(std::move(s)), damage(d) {}
|
||||
std::string name;
|
||||
int32_t damage;
|
||||
};
|
||||
REFLECTION(Weapon, name, damage);
|
||||
|
||||
enum Color : uint8_t { Red, Green, Blue };
|
||||
|
||||
struct Monster : public iguana::base_impl<Monster> {
|
||||
Monster() = default;
|
||||
Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, Color f,
|
||||
std::vector<Weapon> g, Weapon h, std::vector<Vec3> i) {}
|
||||
Vec3 pos;
|
||||
int32_t mana;
|
||||
int32_t hp;
|
||||
std::string name;
|
||||
std::string inventory;
|
||||
Color color;
|
||||
std::vector<Weapon> weapons;
|
||||
Weapon equipped;
|
||||
std::vector<Vec3> path;
|
||||
};
|
||||
REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped,
|
||||
path);
|
||||
|
||||
struct Monsters : public iguana::base_impl<Monsters> {
|
||||
Monsters() = default;
|
||||
explicit Monsters(std::vector<Monster> l) : list(std::move(l)) {}
|
||||
std::vector<Monster> list;
|
||||
};
|
||||
REFLECTION(Monsters, list);
|
||||
|
||||
inline auto create_rects(size_t object_count) {
|
||||
rect rc{1, 0, 11, 1};
|
||||
std::vector<rect> v{};
|
||||
for (std::size_t i = 0; i < object_count; i++) {
|
||||
v.push_back(rc);
|
||||
}
|
||||
return rcs;
|
||||
return v;
|
||||
}
|
||||
inline auto create_persons(std::size_t object_count) {
|
||||
persons ps;
|
||||
for (int i = 0; i < object_count; ++i) {
|
||||
person p{.id = 432798,
|
||||
.name = std::string(1024, 'A'),
|
||||
.age = 24,
|
||||
.salary = 65536.42};
|
||||
ps.person_list.emplace_back(p);
|
||||
|
||||
inline auto create_persons(size_t object_count) {
|
||||
std::vector<person> v{};
|
||||
person p{432798, std::string(1024, 'A'), 24, 65536.42};
|
||||
|
||||
for (std::size_t i = 0; i < object_count; i++) {
|
||||
v.push_back(p);
|
||||
}
|
||||
return ps;
|
||||
return v;
|
||||
}
|
||||
inline auto create_monsters(std::size_t object_count) {
|
||||
Monsters monsters;
|
||||
for (int i = 0; i < object_count / 2; ++i) {
|
||||
{
|
||||
Monster m{};
|
||||
m.pos = std::make_unique<struct_pb_sample::Vec3>();
|
||||
*m.pos = struct_pb_sample::Vec3{1, 2, 3};
|
||||
// m.pos = {1, 2, 3};
|
||||
m.mana = 16;
|
||||
m.hp = 24;
|
||||
m.name = "it is a test";
|
||||
m.inventory = "\1\2\3\4";
|
||||
m.color = Monster::Color::Red;
|
||||
m.weapons = {{"gun", 42}, {"shotgun", 56}};
|
||||
m.equipped = std::make_unique<struct_pb_sample::Weapon>();
|
||||
*m.equipped = struct_pb_sample::Weapon{"air craft", 67};
|
||||
// m.equipped = {"air craft", 67};
|
||||
m.path = {{7, 8, 9}, {71, 81, 91}};
|
||||
monsters.monsters.push_back(std::move(m));
|
||||
}
|
||||
{
|
||||
Monster m;
|
||||
m.pos = std::make_unique<struct_pb_sample::Vec3>();
|
||||
*m.pos = struct_pb_sample::Vec3{11, 22, 33};
|
||||
m.mana = 161;
|
||||
m.hp = 241;
|
||||
m.name = "it is a test, ok";
|
||||
m.inventory = "\24\25\26\24";
|
||||
m.color = Monster::Color::Red;
|
||||
m.weapons = {{"gun", 421}, {"shotgun", 561}};
|
||||
m.equipped = std::make_unique<struct_pb_sample::Weapon>();
|
||||
*m.equipped = struct_pb_sample::Weapon{"air craft", 671};
|
||||
// m.equipped = {"air craft", 671};
|
||||
m.path = {{71, 82, 93}, {711, 821, 931}};
|
||||
monsters.monsters.push_back(std::move(m));
|
||||
}
|
||||
|
||||
inline std::vector<Monster> create_monsters(size_t object_count) {
|
||||
std::vector<Monster> v{};
|
||||
Monster m = {
|
||||
Vec3{1, 2, 3},
|
||||
16,
|
||||
24,
|
||||
"it is a test",
|
||||
"\1\2\3\4",
|
||||
Color::Red,
|
||||
{{"gun", 42}, {"shotgun", 56}},
|
||||
{"air craft", 67},
|
||||
{{7, 8, 9}, {71, 81, 91}},
|
||||
};
|
||||
|
||||
Monster m1 = {
|
||||
{11, 22, 33},
|
||||
161,
|
||||
241,
|
||||
"it is a test, ok",
|
||||
"\24\25\26\24",
|
||||
Color::Red,
|
||||
{{"gun", 421}, {"shotgun", 561}},
|
||||
{"air craft", 671},
|
||||
{{71, 82, 93}, {711, 821, 931}},
|
||||
};
|
||||
|
||||
for (std::size_t i = 0; i < object_count / 2; i++) {
|
||||
v.push_back(m);
|
||||
v.push_back(m1);
|
||||
}
|
||||
|
||||
if (object_count % 2 == 1) {
|
||||
Monster m{};
|
||||
m.pos = std::make_unique<struct_pb_sample::Vec3>();
|
||||
*m.pos = struct_pb_sample::Vec3{1, 2, 3};
|
||||
// m.pos = {1, 2, 3};
|
||||
m.mana = 16;
|
||||
m.hp = 24;
|
||||
m.name = "it is a test";
|
||||
m.inventory = "\1\2\3\4";
|
||||
m.color = Monster::Color::Red;
|
||||
m.weapons = {{"gun", 42}, {"shotgun", 56}};
|
||||
m.equipped = std::make_unique<struct_pb_sample::Weapon>();
|
||||
*m.equipped = struct_pb_sample::Weapon{"air craft", 67};
|
||||
// m.equipped = {"air craft", 67};
|
||||
m.path = {{7, 8, 9}, {71, 81, 91}};
|
||||
monsters.monsters.push_back(std::move(m));
|
||||
v.push_back(m);
|
||||
}
|
||||
return monsters;
|
||||
}
|
||||
|
||||
struct struct_pb_sample_t : public base_sample {
|
||||
return v;
|
||||
}
|
||||
} // namespace pb_sample
|
||||
|
||||
struct struct_pb_sample : public base_sample {
|
||||
static inline constexpr LibType lib_type = LibType::STRUCT_PB;
|
||||
std::string name() const override { return get_lib_name(lib_type); }
|
||||
|
||||
void create_samples() override {
|
||||
rects_ = struct_pb_sample::create_rects(OBJECT_COUNT);
|
||||
persons_ = struct_pb_sample::create_persons(OBJECT_COUNT);
|
||||
monsters_ = struct_pb_sample::create_monsters(OBJECT_COUNT);
|
||||
rects_.list = {pb_sample::create_rects(OBJECT_COUNT)};
|
||||
persons_.list = {pb_sample::create_persons(OBJECT_COUNT)};
|
||||
monsters_.list = {pb_sample::create_monsters(OBJECT_COUNT)};
|
||||
}
|
||||
|
||||
void do_serialization() override {
|
||||
serialize(SampleType::RECT, rects_.rect32_list[0]);
|
||||
serialize(SampleType::RECT, rects_.list[0]);
|
||||
struct_pb::to_pb(rects_, buffer_);
|
||||
struct_pb::to_pb(rects_, buffer_);
|
||||
struct_pb::to_pb(rects_, buffer_);
|
||||
std::cout << rects_.list.size() << "\n";
|
||||
serialize(SampleType::RECTS, rects_);
|
||||
serialize(SampleType::PERSON, persons_.person_list[0]);
|
||||
serialize(SampleType::PERSON, persons_.list[0]);
|
||||
serialize(SampleType::PERSONS, persons_);
|
||||
serialize(SampleType::MONSTER, monsters_.monsters[0]);
|
||||
serialize(SampleType::MONSTER, monsters_.list[0]);
|
||||
serialize(SampleType::MONSTERS, monsters_);
|
||||
}
|
||||
|
||||
void do_deserialization() override {
|
||||
deserialize(SampleType::RECT, rects_.rect32_list[0]);
|
||||
deserialize(SampleType::RECT, rects_.list[0]);
|
||||
deserialize(SampleType::RECTS, rects_);
|
||||
deserialize(SampleType::PERSON, persons_.person_list[0]);
|
||||
deserialize(SampleType::PERSON, persons_.list[0]);
|
||||
deserialize(SampleType::PERSONS, persons_);
|
||||
deserialize(SampleType::MONSTER, monsters_.monsters[0]);
|
||||
deserialize(SampleType::MONSTER, monsters_.list[0]);
|
||||
deserialize(SampleType::MONSTERS, monsters_);
|
||||
}
|
||||
|
||||
private:
|
||||
template <typename T>
|
||||
void serialize(SampleType sample_type, T& sample) {
|
||||
auto sz = struct_pb::internal::get_needed_size(sample);
|
||||
buffer_.resize(sz);
|
||||
struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample);
|
||||
buffer_.clear();
|
||||
buffer_.resize(sz);
|
||||
|
||||
uint64_t ns = 0;
|
||||
std::string bench_name =
|
||||
name() + " serialize " + get_sample_name(sample_type);
|
||||
|
||||
void serialize(SampleType sample_type, T &sample) {
|
||||
{
|
||||
ScopedTimer timer(bench_name.data(), ns);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
buffer_.clear();
|
||||
auto sz = struct_pb::internal::get_needed_size(sample);
|
||||
buffer_.resize(sz);
|
||||
struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(),
|
||||
sample);
|
||||
no_op(buffer_);
|
||||
no_op((char*)&sample);
|
||||
}
|
||||
}
|
||||
struct_pb::to_pb(sample, buffer_);
|
||||
buffer_.clear();
|
||||
|
||||
ser_time_elapsed_map_.emplace(sample_type, ns);
|
||||
uint64_t ns = 0;
|
||||
std::string bench_name =
|
||||
name() + " serialize " + get_sample_name(sample_type);
|
||||
|
||||
{
|
||||
ScopedTimer timer(bench_name.data(), ns);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
struct_pb::to_pb(sample, buffer_);
|
||||
no_op(buffer_);
|
||||
no_op((char *)&sample);
|
||||
}
|
||||
}
|
||||
ser_time_elapsed_map_.emplace(sample_type, ns);
|
||||
}
|
||||
buf_size_map_.emplace(sample_type, buffer_.size());
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deserialize(SampleType sample_type, T& sample) {
|
||||
template <typename T, typename U = T>
|
||||
void deserialize(SampleType sample_type, T &sample) {
|
||||
buffer_.clear();
|
||||
auto sz = struct_pb::internal::get_needed_size(sample);
|
||||
buffer_.resize(sz);
|
||||
struct_pb::internal::serialize_to(buffer_.data(), buffer_.size(), sample);
|
||||
|
||||
T obj;
|
||||
// vec.resize(ITERATIONS);
|
||||
struct_pb::to_pb(sample, buffer_);
|
||||
|
||||
uint64_t ns = 0;
|
||||
std::string bench_name =
|
||||
|
|
@ -165,21 +211,17 @@ struct struct_pb_sample_t : public base_sample {
|
|||
{
|
||||
ScopedTimer timer(bench_name.data(), ns);
|
||||
for (int i = 0; i < ITERATIONS; ++i) {
|
||||
[[maybe_unused]] auto ok = struct_pb::internal::deserialize_to(
|
||||
obj, buffer_.data(), buffer_.size());
|
||||
assert(ok);
|
||||
no_op((char*)&obj);
|
||||
U obj;
|
||||
struct_pb::from_pb(obj, buffer_);
|
||||
no_op((char *)&obj);
|
||||
no_op(buffer_);
|
||||
}
|
||||
}
|
||||
deser_time_elapsed_map_.emplace(sample_type, ns);
|
||||
|
||||
buf_size_map_.emplace(sample_type, buffer_.size());
|
||||
}
|
||||
|
||||
struct_pb_sample::rect32s rects_;
|
||||
struct_pb_sample::persons persons_;
|
||||
struct_pb_sample::Monsters monsters_;
|
||||
pb_sample::rects rects_;
|
||||
pb_sample::persons persons_;
|
||||
pb_sample::Monsters monsters_;
|
||||
std::string buffer_;
|
||||
};
|
||||
} // namespace struct_pb_sample
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
add_subdirectory(protoc-plugin)
|
||||
add_subdirectory(conformance)
|
||||
|
|
@ -1,68 +0,0 @@
|
|||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests/struct_pb)
|
||||
find_package(Protobuf QUIET)
|
||||
if (NOT Protobuf_FOUND)
|
||||
message(INFO "to build struct_pb conformance test, you must install libprotoc first")
|
||||
return()
|
||||
endif ()
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
add_executable(conformance_test_runner
|
||||
binary_json_conformance_suite.cc
|
||||
binary_json_conformance_suite.h
|
||||
conformance_test_runner.cc
|
||||
conformance_test_main.cc
|
||||
conformance_test.cc
|
||||
conformance_test.h
|
||||
)
|
||||
target_sources(conformance_test_runner PRIVATE
|
||||
conformance/conformance.proto
|
||||
google/protobuf/test_messages_proto2.proto
|
||||
google/protobuf/test_messages_proto3.proto
|
||||
)
|
||||
protobuf_generate(TARGET conformance_test_runner)
|
||||
target_include_directories(conformance_test_runner PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_link_libraries(conformance_test_runner PRIVATE protobuf::libprotobuf)
|
||||
add_executable(conformance_cpp conformance_cpp.cc)
|
||||
target_link_libraries(conformance_cpp PRIVATE protobuf::libprotobuf)
|
||||
target_sources(conformance_cpp PRIVATE
|
||||
conformance/conformance.proto
|
||||
google/protobuf/test_messages_proto2.proto
|
||||
google/protobuf/test_messages_proto3.proto
|
||||
)
|
||||
protobuf_generate(TARGET conformance_cpp)
|
||||
target_include_directories(conformance_cpp PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
add_test(NAME conformance_cpp_test
|
||||
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner
|
||||
--failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt
|
||||
--output_dir ${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_cpp
|
||||
DEPENDS conformance_test_runner conformance_cpp)
|
||||
|
||||
add_executable(conformance_struct_pb
|
||||
conformance_struct_pb.cc
|
||||
)
|
||||
protobuf_generate_struct_pb(SRCS HDRS
|
||||
conformance/conformance.proto
|
||||
google/protobuf/test_messages_proto2.proto
|
||||
google/protobuf/test_messages_proto3.proto
|
||||
google/protobuf/any.proto
|
||||
google/protobuf/descriptor.proto
|
||||
google/protobuf/duration.proto
|
||||
google/protobuf/field_mask.proto
|
||||
google/protobuf/struct.proto
|
||||
google/protobuf/timestamp.proto
|
||||
google/protobuf/type.proto
|
||||
google/protobuf/wrappers.proto
|
||||
google/protobuf/source_context.proto
|
||||
TARGET conformance_struct_pb
|
||||
)
|
||||
target_sources(conformance_struct_pb PRIVATE ${SRCS} ${HDRS})
|
||||
target_include_directories(conformance_struct_pb PRIVATE ${CMAKE_CURRENT_BINARY_DIR})
|
||||
|
||||
|
||||
add_test(NAME conformance_struct_pb_test
|
||||
COMMAND ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_test_runner
|
||||
--failure_list ${CMAKE_CURRENT_SOURCE_DIR}/failure_list_cpp.txt
|
||||
--output_dir ${CMAKE_CURRENT_BINARY_DIR}
|
||||
${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/conformance_struct_pb
|
||||
DEPENDS conformance_test_runner conformance_struct_pb)
|
||||
|
|
@ -1,208 +0,0 @@
|
|||
#pragma once
|
||||
// absl compat
|
||||
#include <iostream>
|
||||
#include <string_view>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
// #include "google/protobuf/stubs/status.h"
|
||||
namespace absl {
|
||||
// using namespace google::protobuf::util;
|
||||
enum class StatusCode : int {
|
||||
kOk = 0,
|
||||
kCancelled = 1,
|
||||
kUnknown = 2,
|
||||
kInvalidArgument = 3,
|
||||
kDeadlineExceeded = 4,
|
||||
kNotFound = 5,
|
||||
kAlreadyExists = 6,
|
||||
kPermissionDenied = 7,
|
||||
kResourceExhausted = 8,
|
||||
kFailedPrecondition = 9,
|
||||
kAborted = 10,
|
||||
kOutOfRange = 11,
|
||||
kUnimplemented = 12,
|
||||
kInternal = 13,
|
||||
kUnavailable = 14,
|
||||
kDataLoss = 15,
|
||||
kUnauthenticated = 16,
|
||||
};
|
||||
class Status {
|
||||
public:
|
||||
Status(StatusCode code = StatusCode::kOk, std::string_view message = {})
|
||||
: code_(code), msg_(message) {}
|
||||
bool ok() const { return code_ == StatusCode::kOk; }
|
||||
std::string message() const {
|
||||
// fix gcc 10
|
||||
return std::string(msg_);
|
||||
}
|
||||
|
||||
private:
|
||||
StatusCode code_;
|
||||
std::string_view msg_;
|
||||
friend std::ostream& operator<<(std::ostream& os, const Status& x);
|
||||
};
|
||||
inline std::ostream& operator<<(std::ostream& os, const Status& x) {
|
||||
os << static_cast<int>(x.code_) << " " << x.msg_;
|
||||
return os;
|
||||
}
|
||||
Status DataLossError(std::string_view message) {
|
||||
return Status(absl::StatusCode::kDataLoss, message);
|
||||
}
|
||||
|
||||
StatusCode ErrnoToStatusCode(int error_number) {
|
||||
switch (error_number) {
|
||||
case 0:
|
||||
return StatusCode::kOk;
|
||||
case EINVAL: // Invalid argument
|
||||
case ENAMETOOLONG: // Filename too long
|
||||
case E2BIG: // Argument list too long
|
||||
case EDESTADDRREQ: // Destination address required
|
||||
case EDOM: // Mathematics argument out of domain of function
|
||||
case EFAULT: // Bad address
|
||||
case EILSEQ: // Illegal byte sequence
|
||||
case ENOPROTOOPT: // Protocol not available
|
||||
case ENOSTR: // Not a STREAM
|
||||
case ENOTSOCK: // Not a socket
|
||||
case ENOTTY: // Inappropriate I/O control operation
|
||||
case EPROTOTYPE: // Protocol wrong type for socket
|
||||
case ESPIPE: // Invalid seek
|
||||
return StatusCode::kInvalidArgument;
|
||||
case ETIMEDOUT: // Connection timed out
|
||||
case ETIME: // Timer expired
|
||||
return StatusCode::kDeadlineExceeded;
|
||||
case ENODEV: // No such device
|
||||
case ENOENT: // No such file or directory
|
||||
#ifdef ENOMEDIUM
|
||||
case ENOMEDIUM: // No medium found
|
||||
#endif
|
||||
case ENXIO: // No such device or address
|
||||
case ESRCH: // No such process
|
||||
return StatusCode::kNotFound;
|
||||
case EEXIST: // File exists
|
||||
case EADDRNOTAVAIL: // Address not available
|
||||
case EALREADY: // Connection already in progress
|
||||
#ifdef ENOTUNIQ
|
||||
case ENOTUNIQ: // Name not unique on network
|
||||
#endif
|
||||
return StatusCode::kAlreadyExists;
|
||||
case EPERM: // Operation not permitted
|
||||
case EACCES: // Permission denied
|
||||
#ifdef ENOKEY
|
||||
case ENOKEY: // Required key not available
|
||||
#endif
|
||||
case EROFS: // Read only file system
|
||||
return StatusCode::kPermissionDenied;
|
||||
case ENOTEMPTY: // Directory not empty
|
||||
case EISDIR: // Is a directory
|
||||
case ENOTDIR: // Not a directory
|
||||
case EADDRINUSE: // Address already in use
|
||||
case EBADF: // Invalid file descriptor
|
||||
#ifdef EBADFD
|
||||
case EBADFD: // File descriptor in bad state
|
||||
#endif
|
||||
case EBUSY: // Device or resource busy
|
||||
case ECHILD: // No child processes
|
||||
case EISCONN: // Socket is connected
|
||||
#ifdef EISNAM
|
||||
case EISNAM: // Is a named type file
|
||||
#endif
|
||||
#ifdef ENOTBLK
|
||||
case ENOTBLK: // Block device required
|
||||
#endif
|
||||
case ENOTCONN: // The socket is not connected
|
||||
case EPIPE: // Broken pipe
|
||||
#ifdef ESHUTDOWN
|
||||
case ESHUTDOWN: // Cannot send after transport endpoint shutdown
|
||||
#endif
|
||||
case ETXTBSY: // Text file busy
|
||||
#ifdef EUNATCH
|
||||
case EUNATCH: // Protocol driver not attached
|
||||
#endif
|
||||
return StatusCode::kFailedPrecondition;
|
||||
case ENOSPC: // No space left on device
|
||||
#ifdef EDQUOT
|
||||
case EDQUOT: // Disk quota exceeded
|
||||
#endif
|
||||
case EMFILE: // Too many open files
|
||||
case EMLINK: // Too many links
|
||||
case ENFILE: // Too many open files in system
|
||||
case ENOBUFS: // No buffer space available
|
||||
case ENODATA: // No message is available on the STREAM read queue
|
||||
case ENOMEM: // Not enough space
|
||||
case ENOSR: // No STREAM resources
|
||||
#ifdef EUSERS
|
||||
case EUSERS: // Too many users
|
||||
#endif
|
||||
return StatusCode::kResourceExhausted;
|
||||
#ifdef ECHRNG
|
||||
case ECHRNG: // Channel number out of range
|
||||
#endif
|
||||
case EFBIG: // File too large
|
||||
case EOVERFLOW: // Value too large to be stored in data type
|
||||
case ERANGE: // Result too large
|
||||
return StatusCode::kOutOfRange;
|
||||
#ifdef ENOPKG
|
||||
case ENOPKG: // Package not installed
|
||||
#endif
|
||||
case ENOSYS: // Function not implemented
|
||||
case ENOTSUP: // Operation not supported
|
||||
case EAFNOSUPPORT: // Address family not supported
|
||||
#ifdef EPFNOSUPPORT
|
||||
case EPFNOSUPPORT: // Protocol family not supported
|
||||
#endif
|
||||
case EPROTONOSUPPORT: // Protocol not supported
|
||||
#ifdef ESOCKTNOSUPPORT
|
||||
case ESOCKTNOSUPPORT: // Socket type not supported
|
||||
#endif
|
||||
case EXDEV: // Improper link
|
||||
return StatusCode::kUnimplemented;
|
||||
case EAGAIN: // Resource temporarily unavailable
|
||||
#ifdef ECOMM
|
||||
case ECOMM: // Communication error on send
|
||||
#endif
|
||||
case ECONNREFUSED: // Connection refused
|
||||
case ECONNABORTED: // Connection aborted
|
||||
case ECONNRESET: // Connection reset
|
||||
case EINTR: // Interrupted function call
|
||||
#ifdef EHOSTDOWN
|
||||
case EHOSTDOWN: // Host is down
|
||||
#endif
|
||||
case EHOSTUNREACH: // Host is unreachable
|
||||
case ENETDOWN: // Network is down
|
||||
case ENETRESET: // Connection aborted by network
|
||||
case ENETUNREACH: // Network unreachable
|
||||
case ENOLCK: // No locks available
|
||||
case ENOLINK: // Link has been severed
|
||||
#ifdef ENONET
|
||||
case ENONET: // Machine is not on the network
|
||||
#endif
|
||||
return StatusCode::kUnavailable;
|
||||
case EDEADLK: // Resource deadlock avoided
|
||||
#ifdef ESTALE
|
||||
case ESTALE: // Stale file handle
|
||||
#endif
|
||||
return StatusCode::kAborted;
|
||||
case ECANCELED: // Operation cancelled
|
||||
return StatusCode::kCancelled;
|
||||
default:
|
||||
return StatusCode::kUnknown;
|
||||
}
|
||||
}
|
||||
std::string MessageForErrnoToStatus(int error_number, std::string message) {
|
||||
return message + ": " + std::to_string(error_number);
|
||||
}
|
||||
Status ErrnoToStatus(int error_number, std::string message) {
|
||||
return Status(ErrnoToStatusCode(error_number),
|
||||
MessageForErrnoToStatus(error_number, message));
|
||||
}
|
||||
inline Status OkStatus() { return Status(); }
|
||||
Status NotFoundError(std::string_view message) {
|
||||
return Status(absl::StatusCode::kNotFound, message);
|
||||
}
|
||||
Status InvalidArgumentError(std::string_view message) {
|
||||
return Status(absl::StatusCode::kInvalidArgument, message);
|
||||
}
|
||||
Status UnimplementedError(std::string_view message) {
|
||||
return Status(absl::StatusCode::kUnimplemented, message);
|
||||
}
|
||||
} // namespace absl
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
// absl compat
|
||||
#include "status.h"
|
||||
|
||||
namespace absl {
|
||||
template <typename T>
|
||||
class StatusOr {
|
||||
public:
|
||||
StatusOr(Status status) : status_(status) {}
|
||||
StatusOr(const T& data) : data_(data) {}
|
||||
Status status() const { return status_; }
|
||||
T* operator->() { return &data_; }
|
||||
bool ok() const { return status_.ok(); }
|
||||
const T& operator*() const& { return data_; }
|
||||
|
||||
private:
|
||||
Status status_;
|
||||
T data_;
|
||||
};
|
||||
} // namespace absl
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
#pragma
|
||||
#include <string>
|
||||
|
||||
// #include "google/protobuf/stubs/strutil.h"
|
||||
// compat for absl::StrCat
|
||||
namespace absl {
|
||||
// using google::protobuf::StrCat;
|
||||
template <typename T>
|
||||
std::string StrCat(const T& t) {
|
||||
if constexpr (std::same_as<T, std::string>) {
|
||||
return t;
|
||||
}
|
||||
else if constexpr (std::integral<T>) {
|
||||
return std::to_string(t);
|
||||
}
|
||||
else if constexpr (std::is_enum_v<T>) {
|
||||
int n = static_cast<int>(t);
|
||||
return std::to_string(n);
|
||||
}
|
||||
else {
|
||||
return std::string(t);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T, typename... Args>
|
||||
std::string StrCat(const T& t, const Args&... args) {
|
||||
return StrCat(t) + StrCat(args...);
|
||||
}
|
||||
} // namespace absl
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
// compat only
|
||||
namespace absl {
|
||||
template <typename T>
|
||||
auto to(const T& t) {
|
||||
if constexpr (std::same_as<T, std::string>) {
|
||||
return t.c_str();
|
||||
}
|
||||
else {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
class SimpleAppender {
|
||||
public:
|
||||
SimpleAppender(std::string& buffer, std::string_view format)
|
||||
: buffer(buffer), format_(format) {}
|
||||
void format() {
|
||||
buffer += format_.substr(index);
|
||||
index = format_.size();
|
||||
}
|
||||
template <typename T, typename... Args>
|
||||
void format(const T& t, const Args&... args) {
|
||||
while (index < format_.size()) {
|
||||
if (format_[index] != '%') {
|
||||
buffer += format_[index];
|
||||
index++;
|
||||
continue;
|
||||
}
|
||||
if (index + 1 < format_.size()) {
|
||||
if (format_[index + 1] == 's') {
|
||||
if constexpr (std::same_as<std::string, T>) {
|
||||
buffer += t;
|
||||
}
|
||||
else if constexpr (std::same_as<std::string_view, T>) {
|
||||
buffer += t;
|
||||
}
|
||||
else if constexpr (std::same_as<char*, std::decay_t<T>>) {
|
||||
buffer += std::string(t);
|
||||
}
|
||||
else {
|
||||
buffer += "'ERROR FORMAT'";
|
||||
}
|
||||
index++;
|
||||
index++;
|
||||
format(args...);
|
||||
}
|
||||
else if (format_[index + 1] == 'd') {
|
||||
if constexpr (std::integral<T>) {
|
||||
buffer += std::to_string(t);
|
||||
}
|
||||
else {
|
||||
buffer += "'ERROR FORMAT'";
|
||||
}
|
||||
index++;
|
||||
index++;
|
||||
format(args...);
|
||||
}
|
||||
else if (format_[index + 1] == 'z') {
|
||||
if (index + 2 < format_.size() && format_[index + 2] == 'u') {
|
||||
if constexpr (std::integral<T>) {
|
||||
buffer += std::to_string(t);
|
||||
}
|
||||
else {
|
||||
buffer += "'ERROR FORMAT'";
|
||||
}
|
||||
index++;
|
||||
index++;
|
||||
index++;
|
||||
format(args...);
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
buffer += "'maybe ERROR FORMAT'";
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
std::string& buffer;
|
||||
std::string_view format_;
|
||||
int index = 0;
|
||||
};
|
||||
template <typename... Args>
|
||||
void StrAppendFormat(std::string* output, const char* format,
|
||||
const Args&... args) {
|
||||
SimpleAppender(*output, format).format(args...);
|
||||
// std::cout << "result: " << *output << std::endl;
|
||||
}
|
||||
} // namespace absl
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,123 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#ifndef CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
|
||||
#define CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
|
||||
|
||||
#include "conformance_test.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class BinaryAndJsonConformanceSuite : public ConformanceTestSuite {
|
||||
public:
|
||||
BinaryAndJsonConformanceSuite() {}
|
||||
|
||||
private:
|
||||
void RunSuiteImpl() override;
|
||||
void RunBinaryPerformanceTests();
|
||||
void RunValidJsonTest(const std::string& test_name, ConformanceLevel level,
|
||||
const std::string& input_json,
|
||||
const std::string& equivalent_text_format,
|
||||
bool is_proto3);
|
||||
void RunValidProtobufTest(const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
const std::string& input_protobuf,
|
||||
const std::string& equivalent_text_format,
|
||||
bool is_proto3);
|
||||
void RunValidBinaryProtobufTest(const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
const std::string& input_protobuf,
|
||||
bool is_proto3);
|
||||
void RunValidBinaryProtobufTest(const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
const std::string& input_protobuf,
|
||||
const std::string& expected_protobuf,
|
||||
bool is_proto3);
|
||||
void RunBinaryPerformanceMergeMessageWithField(const std::string& test_name,
|
||||
const std::string& field_proto,
|
||||
bool is_proto3);
|
||||
|
||||
void RunValidProtobufTestWithMessage(
|
||||
const std::string& test_name, ConformanceLevel level,
|
||||
const Message* input, const std::string& equivalent_text_format,
|
||||
bool is_proto3);
|
||||
|
||||
bool ParseResponse(const conformance::ConformanceResponse& response,
|
||||
const ConformanceRequestSetting& setting,
|
||||
Message* test_message) override;
|
||||
void ExpectParseFailureForJson(const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
const std::string& input_json);
|
||||
void ExpectSerializeFailureForJson(const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
const std::string& text_format);
|
||||
void ExpectParseFailureForProtoWithProtoVersion(const std::string& proto,
|
||||
const std::string& test_name,
|
||||
ConformanceLevel level,
|
||||
bool is_proto3);
|
||||
void ExpectParseFailureForProto(const std::string& proto,
|
||||
const std::string& test_name,
|
||||
ConformanceLevel level);
|
||||
void ExpectHardParseFailureForProto(const std::string& proto,
|
||||
const std::string& test_name,
|
||||
ConformanceLevel level);
|
||||
void TestPrematureEOFForType(google::protobuf::FieldDescriptor::Type type);
|
||||
void TestIllegalTags();
|
||||
template <class MessageType>
|
||||
void TestOneofMessage(MessageType& message, bool is_proto3);
|
||||
template <class MessageType>
|
||||
void TestUnknownMessage(MessageType& message, bool is_proto3);
|
||||
void TestValidDataForType(
|
||||
google::protobuf::FieldDescriptor::Type,
|
||||
std::vector<std::pair<std::string, std::string>> values);
|
||||
void TestValidDataForRepeatedScalarMessage();
|
||||
void TestValidDataForMapType(google::protobuf::FieldDescriptor::Type,
|
||||
google::protobuf::FieldDescriptor::Type);
|
||||
void TestValidDataForOneofType(google::protobuf::FieldDescriptor::Type);
|
||||
void TestMergeOneofMessage();
|
||||
void TestOverwriteMessageValueMap();
|
||||
void TestBinaryPerformanceForAlternatingUnknownFields();
|
||||
void TestBinaryPerformanceMergeMessageWithRepeatedFieldForType(
|
||||
google::protobuf::FieldDescriptor::Type);
|
||||
void TestBinaryPerformanceMergeMessageWithUnknownFieldForType(
|
||||
google::protobuf::FieldDescriptor::Type);
|
||||
void TestJsonPerformanceMergeMessageWithRepeatedFieldForType(
|
||||
google::protobuf::FieldDescriptor::Type, std::string field_value);
|
||||
|
||||
std::unique_ptr<google::protobuf::util::TypeResolver> type_resolver_;
|
||||
std::string type_url_;
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // CONFORMANCE_BINARY_JSON_CONFORMANCE_SUITE_H
|
||||
|
|
@ -1,180 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package conformance;
|
||||
|
||||
option java_package = "com.google.protobuf.conformance";
|
||||
option objc_class_prefix = "Conformance";
|
||||
|
||||
// This defines the conformance testing protocol. This protocol exists between
|
||||
// the conformance test suite itself and the code being tested. For each test,
|
||||
// the suite will send a ConformanceRequest message and expect a
|
||||
// ConformanceResponse message.
|
||||
//
|
||||
// You can either run the tests in two different ways:
|
||||
//
|
||||
// 1. in-process (using the interface in conformance_test.h).
|
||||
//
|
||||
// 2. as a sub-process communicating over a pipe. Information about how to
|
||||
// do this is in conformance_test_runner.cc.
|
||||
//
|
||||
// Pros/cons of the two approaches:
|
||||
//
|
||||
// - running as a sub-process is much simpler for languages other than C/C++.
|
||||
//
|
||||
// - running as a sub-process may be more tricky in unusual environments like
|
||||
// iOS apps, where fork/stdin/stdout are not available.
|
||||
|
||||
enum WireFormat {
|
||||
UNSPECIFIED = 0;
|
||||
PROTOBUF = 1;
|
||||
JSON = 2;
|
||||
JSPB = 3; // Only used inside Google. Opensource testees just skip it.
|
||||
TEXT_FORMAT = 4;
|
||||
}
|
||||
|
||||
enum TestCategory {
|
||||
UNSPECIFIED_TEST = 0;
|
||||
BINARY_TEST = 1; // Test binary wire format.
|
||||
JSON_TEST = 2; // Test json wire format.
|
||||
// Similar to JSON_TEST. However, during parsing json, testee should ignore
|
||||
// unknown fields. This feature is optional. Each implementation can decide
|
||||
// whether to support it. See
|
||||
// https://developers.google.com/protocol-buffers/docs/proto3#json_options
|
||||
// for more detail.
|
||||
JSON_IGNORE_UNKNOWN_PARSING_TEST = 3;
|
||||
// Test jspb wire format. Only used inside Google. Opensource testees just
|
||||
// skip it.
|
||||
JSPB_TEST = 4;
|
||||
// Test text format. For cpp, java and python, testees can already deal with
|
||||
// this type. Testees of other languages can simply skip it.
|
||||
TEXT_FORMAT_TEST = 5;
|
||||
}
|
||||
|
||||
// The conformance runner will request a list of failures as the first request.
|
||||
// This will be known by message_type == "conformance.FailureSet", a conformance
|
||||
// test should return a serialized FailureSet in protobuf_payload.
|
||||
message FailureSet {
|
||||
repeated string failure = 1;
|
||||
}
|
||||
|
||||
// Represents a single test case's input. The testee should:
|
||||
//
|
||||
// 1. parse this proto (which should always succeed)
|
||||
// 2. parse the protobuf or JSON payload in "payload" (which may fail)
|
||||
// 3. if the parse succeeded, serialize the message in the requested format.
|
||||
message ConformanceRequest {
|
||||
// The payload (whether protobuf of JSON) is always for a
|
||||
// protobuf_test_messages.proto3.TestAllTypes proto (as defined in
|
||||
// src/google/protobuf/proto3_test_messages.proto).
|
||||
oneof payload {
|
||||
bytes protobuf_payload = 1;
|
||||
string json_payload = 2;
|
||||
// Only used inside Google. Opensource testees just skip it.
|
||||
string jspb_payload = 7;
|
||||
string text_payload = 8;
|
||||
}
|
||||
|
||||
// Which format should the testee serialize its message to?
|
||||
WireFormat requested_output_format = 3;
|
||||
|
||||
// The full name for the test message to use; for the moment, either:
|
||||
// protobuf_test_messages.proto3.TestAllTypesProto3 or
|
||||
// protobuf_test_messages.google.protobuf.TestAllTypesProto2.
|
||||
string message_type = 4;
|
||||
|
||||
// Each test is given a specific test category. Some category may need
|
||||
// specific support in testee programs. Refer to the definition of
|
||||
// TestCategory for more information.
|
||||
TestCategory test_category = 5;
|
||||
|
||||
// Specify details for how to encode jspb.
|
||||
JspbEncodingConfig jspb_encoding_options = 6;
|
||||
|
||||
// This can be used in json and text format. If true, testee should print
|
||||
// unknown fields instead of ignore. This feature is optional.
|
||||
bool print_unknown_fields = 9;
|
||||
}
|
||||
|
||||
// Represents a single test case's output.
|
||||
message ConformanceResponse {
|
||||
oneof result {
|
||||
// This string should be set to indicate parsing failed. The string can
|
||||
// provide more information about the parse error if it is available.
|
||||
//
|
||||
// Setting this string does not necessarily mean the testee failed the
|
||||
// test. Some of the test cases are intentionally invalid input.
|
||||
string parse_error = 1;
|
||||
|
||||
// If the input was successfully parsed but errors occurred when
|
||||
// serializing it to the requested output format, set the error message in
|
||||
// this field.
|
||||
string serialize_error = 6;
|
||||
|
||||
// This should be set if the test program timed out. The string should
|
||||
// provide more information about what the child process was doing when it
|
||||
// was killed.
|
||||
string timeout_error = 9;
|
||||
|
||||
// This should be set if some other error occurred. This will always
|
||||
// indicate that the test failed. The string can provide more information
|
||||
// about the failure.
|
||||
string runtime_error = 2;
|
||||
|
||||
// If the input was successfully parsed and the requested output was
|
||||
// protobuf, serialize it to protobuf and set it in this field.
|
||||
bytes protobuf_payload = 3;
|
||||
|
||||
// If the input was successfully parsed and the requested output was JSON,
|
||||
// serialize to JSON and set it in this field.
|
||||
string json_payload = 4;
|
||||
|
||||
// For when the testee skipped the test, likely because a certain feature
|
||||
// wasn't supported, like JSON input/output.
|
||||
string skipped = 5;
|
||||
|
||||
// If the input was successfully parsed and the requested output was JSPB,
|
||||
// serialize to JSPB and set it in this field. JSPB is only used inside
|
||||
// Google. Opensource testees can just skip it.
|
||||
string jspb_payload = 7;
|
||||
|
||||
// If the input was successfully parsed and the requested output was
|
||||
// TEXT_FORMAT, serialize to TEXT_FORMAT and set it in this field.
|
||||
string text_payload = 8;
|
||||
}
|
||||
}
|
||||
|
||||
// Encoding options for jspb format.
|
||||
message JspbEncodingConfig {
|
||||
// Encode the value field of Any as jspb array if true, otherwise binary.
|
||||
bool use_jspb_array_any_format = 1;
|
||||
}
|
||||
|
|
@ -1,304 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "conformance/conformance.pb.h"
|
||||
#include "google/protobuf/message.h"
|
||||
#include "google/protobuf/stubs/logging.h"
|
||||
#include "google/protobuf/test_messages_proto2.pb.h"
|
||||
#include "google/protobuf/test_messages_proto3.pb.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "google/protobuf/util/json_util.h"
|
||||
#include "google/protobuf/util/type_resolver.h"
|
||||
#include "google/protobuf/util/type_resolver_util.h"
|
||||
|
||||
// Must be included last.
|
||||
#include "google/protobuf/port_def.inc"
|
||||
|
||||
#define RETURN_IF_ERROR(expr) \
|
||||
do { \
|
||||
/* Using _status below to avoid capture problems if expr is "status". */ \
|
||||
const absl::Status _status = (expr); \
|
||||
if (PROTOBUF_PREDICT_FALSE(!_status.ok())) \
|
||||
return _status; \
|
||||
} while (0)
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
namespace {
|
||||
using ::conformance::ConformanceRequest;
|
||||
using ::conformance::ConformanceResponse;
|
||||
using ::google::protobuf::util::BinaryToJsonString;
|
||||
using ::google::protobuf::util::JsonParseOptions;
|
||||
using ::google::protobuf::util::JsonToBinaryString;
|
||||
using ::google::protobuf::util::NewTypeResolverForDescriptorPool;
|
||||
using ::google::protobuf::util::TypeResolver;
|
||||
using ::protobuf_test_messages::proto2::TestAllTypesProto2;
|
||||
using ::protobuf_test_messages::proto3::TestAllTypesProto3;
|
||||
|
||||
absl::Status ReadFd(int fd, char* buf, size_t len) {
|
||||
while (len > 0) {
|
||||
ssize_t bytes_read = read(fd, buf, len);
|
||||
|
||||
if (bytes_read == 0) {
|
||||
return absl::DataLossError("unexpected EOF");
|
||||
}
|
||||
|
||||
if (bytes_read < 0) {
|
||||
return absl::ErrnoToStatus(errno, "error reading from test runner");
|
||||
}
|
||||
|
||||
len -= bytes_read;
|
||||
buf += bytes_read;
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status WriteFd(int fd, const void* buf, size_t len) {
|
||||
if (static_cast<size_t>(write(fd, buf, len)) != len) {
|
||||
return absl::ErrnoToStatus(errno, "error reading to test runner");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
// define this macro when you want to debug struct_pb conformance test
|
||||
//
|
||||
#ifdef CONFORMANCE_CPP_DUMP_DATA
|
||||
static int index = 0;
|
||||
void write_to_file(const std::string& buffer, const std::string& tag,
|
||||
const std::string& suffix) {
|
||||
std::string filename = tag + "/" + std::to_string(index) + "." + suffix;
|
||||
std::ofstream ofs;
|
||||
ofs.open(filename, std::ios::out | std::ios::binary);
|
||||
ofs.write(buffer.data(), buffer.size());
|
||||
}
|
||||
#endif
|
||||
class Harness {
|
||||
public:
|
||||
Harness() {
|
||||
google::protobuf::LinkMessageReflection<TestAllTypesProto2>();
|
||||
google::protobuf::LinkMessageReflection<TestAllTypesProto3>();
|
||||
|
||||
resolver_.reset(NewTypeResolverForDescriptorPool(
|
||||
"type.googleapis.com", DescriptorPool::generated_pool()));
|
||||
type_url_ = absl::StrCat("type.googleapis.com/",
|
||||
TestAllTypesProto3::GetDescriptor()->full_name());
|
||||
}
|
||||
|
||||
absl::StatusOr<ConformanceResponse> RunTest(
|
||||
const ConformanceRequest& request);
|
||||
|
||||
// Returns Ok(true) if we're done processing requests.
|
||||
absl::StatusOr<bool> ServeConformanceRequest();
|
||||
|
||||
private:
|
||||
bool verbose_ = false;
|
||||
std::unique_ptr<TypeResolver> resolver_;
|
||||
std::string type_url_;
|
||||
};
|
||||
|
||||
absl::StatusOr<ConformanceResponse> Harness::RunTest(
|
||||
const ConformanceRequest& request) {
|
||||
const Descriptor* descriptor =
|
||||
DescriptorPool::generated_pool()->FindMessageTypeByName(
|
||||
request.message_type());
|
||||
if (descriptor == nullptr) {
|
||||
return absl::NotFoundError(
|
||||
absl::StrCat("No such message type: ", request.message_type()));
|
||||
}
|
||||
|
||||
std::unique_ptr<Message> test_message(
|
||||
MessageFactory::generated_factory()->GetPrototype(descriptor)->New());
|
||||
ConformanceResponse response;
|
||||
|
||||
switch (request.payload_case()) {
|
||||
case ConformanceRequest::kProtobufPayload: {
|
||||
if (!test_message->ParseFromString(request.protobuf_payload())) {
|
||||
response.set_parse_error("parse error (no more details available)");
|
||||
return response;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ConformanceRequest::kJsonPayload: {
|
||||
JsonParseOptions options;
|
||||
options.ignore_unknown_fields =
|
||||
(request.test_category() ==
|
||||
conformance::JSON_IGNORE_UNKNOWN_PARSING_TEST);
|
||||
|
||||
std::string proto_binary;
|
||||
auto status =
|
||||
JsonToBinaryString(resolver_.get(), type_url_, request.json_payload(),
|
||||
&proto_binary, options);
|
||||
if (!status.ok()) {
|
||||
response.set_parse_error(
|
||||
absl::StrCat("parse error: ", status.message()));
|
||||
return response;
|
||||
}
|
||||
|
||||
if (!test_message->ParseFromString(proto_binary)) {
|
||||
response.set_runtime_error(
|
||||
"parsing JSON generated invalid proto output");
|
||||
return response;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
case ConformanceRequest::kTextPayload: {
|
||||
if (!TextFormat::ParseFromString(request.text_payload(),
|
||||
test_message.get())) {
|
||||
response.set_parse_error("parse error (no more details available)");
|
||||
return response;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case ConformanceRequest::PAYLOAD_NOT_SET:
|
||||
return absl::InvalidArgumentError("request didn't have payload");
|
||||
|
||||
default:
|
||||
return absl::InvalidArgumentError(
|
||||
absl::StrCat("unknown payload type", request.payload_case()));
|
||||
}
|
||||
#ifdef CONFORMANCE_CPP_DUMP_DATA
|
||||
write_to_file(test_message->DebugString(), "in", "msg.txt");
|
||||
#endif
|
||||
switch (request.requested_output_format()) {
|
||||
case conformance::UNSPECIFIED:
|
||||
return absl::InvalidArgumentError("unspecified output format");
|
||||
|
||||
case conformance::PROTOBUF: {
|
||||
GOOGLE_CHECK(
|
||||
test_message->SerializeToString(response.mutable_protobuf_payload()));
|
||||
break;
|
||||
}
|
||||
|
||||
case conformance::JSON: {
|
||||
std::string proto_binary;
|
||||
GOOGLE_CHECK(test_message->SerializeToString(&proto_binary));
|
||||
auto status = BinaryToJsonString(resolver_.get(), type_url_, proto_binary,
|
||||
response.mutable_json_payload());
|
||||
if (!status.ok()) {
|
||||
response.set_serialize_error(absl::StrCat(
|
||||
"failed to serialize JSON output: ", status.message()));
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case conformance::TEXT_FORMAT: {
|
||||
TextFormat::Printer printer;
|
||||
printer.SetHideUnknownFields(!request.print_unknown_fields());
|
||||
GOOGLE_CHECK(printer.PrintToString(*test_message,
|
||||
response.mutable_text_payload()));
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
return absl::InvalidArgumentError(absl::StrCat(
|
||||
"unknown output format", request.requested_output_format()));
|
||||
}
|
||||
|
||||
return response;
|
||||
}
|
||||
|
||||
absl::StatusOr<bool> Harness::ServeConformanceRequest() {
|
||||
uint32_t in_len;
|
||||
if (!ReadFd(STDIN_FILENO, reinterpret_cast<char*>(&in_len), sizeof(in_len))
|
||||
.ok()) {
|
||||
// EOF means we're done.
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string serialized_input;
|
||||
serialized_input.resize(in_len);
|
||||
RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len));
|
||||
#ifdef CONFORMANCE_CPP_DUMP_DATA
|
||||
write_to_file(serialized_input, "in", "bin");
|
||||
#endif
|
||||
ConformanceRequest request;
|
||||
GOOGLE_CHECK(request.ParseFromString(serialized_input));
|
||||
#ifdef CONFORMANCE_CPP_DUMP_DATA
|
||||
write_to_file(
|
||||
std::to_string(serialized_input.size()) + "\n" + request.DebugString(),
|
||||
"in", "txt");
|
||||
#endif
|
||||
absl::StatusOr<ConformanceResponse> response = RunTest(request);
|
||||
RETURN_IF_ERROR(response.status());
|
||||
|
||||
std::string serialized_output;
|
||||
response->SerializeToString(&serialized_output);
|
||||
#ifdef CONFORMANCE_CPP_DUMP_DATA
|
||||
write_to_file(serialized_output, "out", "bin");
|
||||
write_to_file(response->DebugString(), "out", "txt");
|
||||
index++;
|
||||
#endif
|
||||
|
||||
uint32_t out_len = static_cast<uint32_t>(serialized_output.size());
|
||||
RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len)));
|
||||
RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len));
|
||||
|
||||
if (verbose_) {
|
||||
GOOGLE_LOG(INFO) << "conformance-cpp: request="
|
||||
<< request.ShortDebugString()
|
||||
<< ", response=" << response->ShortDebugString();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
int main() {
|
||||
google::protobuf::Harness harness;
|
||||
int total_runs = 0;
|
||||
while (true) {
|
||||
auto is_done = harness.ServeConformanceRequest();
|
||||
if (!is_done.ok()) {
|
||||
GOOGLE_LOG(FATAL) << is_done.status().message();
|
||||
}
|
||||
if (*is_done) {
|
||||
break;
|
||||
}
|
||||
total_runs++;
|
||||
}
|
||||
GOOGLE_LOG(INFO) << "conformance-cpp: received EOF from test runner after "
|
||||
<< total_runs << " tests";
|
||||
}
|
||||
|
|
@ -1,242 +0,0 @@
|
|||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <utility>
|
||||
namespace fs = std::filesystem;
|
||||
|
||||
#include "absl/status/status.h"
|
||||
#include "absl/status/statusor.h"
|
||||
#include "conformance/conformance.struct_pb.h"
|
||||
#include "google/protobuf/test_messages_proto2.struct_pb.h"
|
||||
#include "google/protobuf/test_messages_proto3.struct_pb.h"
|
||||
|
||||
#define RETURN_IF_ERROR(expr) \
|
||||
do { \
|
||||
/* Using _status below to avoid capture problems if expr is "status". */ \
|
||||
const absl::Status _status = (expr); \
|
||||
if (!_status.ok()) \
|
||||
return _status; \
|
||||
} while (0)
|
||||
|
||||
using ::conformance::ConformanceRequest;
|
||||
using ::conformance::ConformanceResponse;
|
||||
using ::protobuf_test_messages::proto2::TestAllTypesProto2;
|
||||
using ::protobuf_test_messages::proto3::TestAllTypesProto3;
|
||||
|
||||
absl::Status ReadFd(int fd, char* buf, size_t len) {
|
||||
while (len > 0) {
|
||||
ssize_t bytes_read = read(fd, buf, len);
|
||||
|
||||
if (bytes_read == 0) {
|
||||
return absl::DataLossError("unexpected EOF");
|
||||
}
|
||||
|
||||
if (bytes_read < 0) {
|
||||
return absl::ErrnoToStatus(errno, "error reading from test runner");
|
||||
}
|
||||
|
||||
len -= bytes_read;
|
||||
buf += bytes_read;
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
absl::Status WriteFd(int fd, const void* buf, size_t len) {
|
||||
if (static_cast<size_t>(write(fd, buf, len)) != len) {
|
||||
return absl::ErrnoToStatus(errno, "error reading to test runner");
|
||||
}
|
||||
return absl::OkStatus();
|
||||
}
|
||||
|
||||
class Harness {
|
||||
public:
|
||||
Harness() {}
|
||||
|
||||
absl::StatusOr<ConformanceResponse> RunTest(
|
||||
const ConformanceRequest& request);
|
||||
|
||||
// Returns Ok(true) if we're done processing requests.
|
||||
absl::StatusOr<bool> ServeConformanceRequest();
|
||||
|
||||
private:
|
||||
bool verbose_ = false;
|
||||
std::string type_url_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
absl::StatusOr<ConformanceResponse> run_test(
|
||||
const ConformanceRequest& request) {
|
||||
ConformanceResponse response{};
|
||||
T data{};
|
||||
struct_pb::UnknownFields unknown_fields{};
|
||||
switch (request.payload_case()) {
|
||||
case ConformanceRequest::PayloadCase::protobuf_payload: {
|
||||
const auto& buffer = request.protobuf_payload();
|
||||
bool ok = struct_pb::internal::deserialize_to(
|
||||
data, buffer.data(), buffer.size(), unknown_fields);
|
||||
if (!ok) {
|
||||
response.set_parse_error("parse error (no more details available)");
|
||||
return response;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case ConformanceRequest::PayloadCase::none:
|
||||
return absl::UnimplementedError("payload none");
|
||||
case ConformanceRequest::PayloadCase::json_payload:
|
||||
return absl::UnimplementedError("payload json");
|
||||
case ConformanceRequest::PayloadCase::jspb_payload:
|
||||
return absl::UnimplementedError("payload jspb");
|
||||
case ConformanceRequest::PayloadCase::text_payload:
|
||||
return absl::UnimplementedError("payload text");
|
||||
default: {
|
||||
int num = static_cast<int>(request.payload_case());
|
||||
return absl::UnimplementedError("unknown payload type: " +
|
||||
std::to_string(num));
|
||||
}
|
||||
}
|
||||
switch (request.requested_output_format) {
|
||||
case conformance::WireFormat::PROTOBUF: {
|
||||
response.set_protobuf_payload(
|
||||
struct_pb::serialize<std::string>(data, unknown_fields));
|
||||
break;
|
||||
}
|
||||
case conformance::WireFormat::UNSPECIFIED:
|
||||
return absl::InvalidArgumentError("unspecified output format");
|
||||
case conformance::WireFormat::JSON:
|
||||
return absl::UnimplementedError("output json");
|
||||
case conformance::WireFormat::JSPB:
|
||||
return absl::UnimplementedError("output jspb");
|
||||
case conformance::WireFormat::TEXT_FORMAT:
|
||||
return absl::UnimplementedError("output text");
|
||||
default: {
|
||||
int num = static_cast<int>(request.requested_output_format);
|
||||
return absl::UnimplementedError("unknown output type: " +
|
||||
std::to_string(num));
|
||||
}
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
absl::StatusOr<ConformanceResponse> Harness::RunTest(
|
||||
const ConformanceRequest& request) {
|
||||
std::string pb2 = "protobuf_test_messages.proto2.TestAllTypesProto2";
|
||||
std::string pb3 = "protobuf_test_messages.proto3.TestAllTypesProto3";
|
||||
if (request.message_type == pb2) {
|
||||
using Message = protobuf_test_messages::proto2::TestAllTypesProto2;
|
||||
return run_test<Message>(request);
|
||||
}
|
||||
else if (request.message_type == pb3) {
|
||||
using Message = protobuf_test_messages::proto3::TestAllTypesProto3;
|
||||
return run_test<Message>(request);
|
||||
}
|
||||
else if (request.message_type == "conformance.FailureSet") {
|
||||
return run_test<conformance::FailureSet>(request);
|
||||
}
|
||||
else {
|
||||
return absl::NotFoundError(
|
||||
absl::StrCat("No such message type: ", request.message_type));
|
||||
}
|
||||
}
|
||||
|
||||
absl::StatusOr<bool> Harness::ServeConformanceRequest() {
|
||||
uint32_t in_len;
|
||||
if (!ReadFd(STDIN_FILENO, reinterpret_cast<char*>(&in_len), sizeof(in_len))
|
||||
.ok()) {
|
||||
// EOF means we're done.
|
||||
return true;
|
||||
}
|
||||
|
||||
std::string serialized_input;
|
||||
serialized_input.resize(in_len);
|
||||
RETURN_IF_ERROR(ReadFd(STDIN_FILENO, &serialized_input[0], in_len));
|
||||
|
||||
ConformanceRequest request{};
|
||||
const auto& buffer = serialized_input;
|
||||
bool ok = struct_pb::internal::deserialize_to(request, buffer.data(),
|
||||
buffer.size());
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
|
||||
absl::StatusOr<ConformanceResponse> response = RunTest(request);
|
||||
RETURN_IF_ERROR(response.status());
|
||||
|
||||
std::string serialized_output = struct_pb::serialize<std::string>(*response);
|
||||
|
||||
uint32_t out_len = static_cast<uint32_t>(serialized_output.size());
|
||||
RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, &out_len, sizeof(out_len)));
|
||||
RETURN_IF_ERROR(WriteFd(STDOUT_FILENO, serialized_output.data(), out_len));
|
||||
if (verbose_) {
|
||||
std::cerr << "conformance-cpp: request=";
|
||||
std::cerr << request.message_type << std::endl;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Harness harness;
|
||||
int total_runs = 0;
|
||||
while (true) {
|
||||
auto is_done = harness.ServeConformanceRequest();
|
||||
if (!is_done.ok()) {
|
||||
std::cerr << is_done.status();
|
||||
}
|
||||
if (*is_done) {
|
||||
break;
|
||||
}
|
||||
total_runs++;
|
||||
}
|
||||
std::cerr << "conformance-struct_pb: received EOF from test runner after ";
|
||||
std::cerr << total_runs << " tests" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// the following code is useful for debugging when struct_pb conformance test
|
||||
// failed.
|
||||
//
|
||||
|
||||
std::string read_file(const std::string& tag, int index,
|
||||
const std::string& suffix) {
|
||||
std::string filename = tag + "/" + std::to_string(index) + "." + suffix;
|
||||
std::ifstream ifs;
|
||||
ifs.open(filename, std::ios::in | std::ios::binary);
|
||||
std::size_t sz = fs::file_size(filename);
|
||||
std::string buffer;
|
||||
buffer.resize(sz);
|
||||
ifs.read(buffer.data(), buffer.size());
|
||||
return buffer;
|
||||
}
|
||||
int debug_struct_pb() {
|
||||
Harness harness;
|
||||
int index = 0;
|
||||
while (index < 1283) {
|
||||
// use data generated by conformance_cpp
|
||||
auto in_buf = read_file("in", index, "bin");
|
||||
auto out_buf = read_file("out", index, "bin");
|
||||
ConformanceRequest req{};
|
||||
bool ok =
|
||||
struct_pb::internal::deserialize_to(req, in_buf.data(), in_buf.size());
|
||||
if (!ok) {
|
||||
std::cout << "ERROR: " << index << " decode" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
auto ret = harness.RunTest(req);
|
||||
if (!ret.ok()) {
|
||||
std::cout << "ERROR: " << index << " run test" << std::endl;
|
||||
return 2;
|
||||
}
|
||||
auto buf = struct_pb::serialize<std::string>(*ret);
|
||||
if (buf != out_buf) {
|
||||
std::cout << "ERROR: " << index << " test fail" << std::endl;
|
||||
return 3;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,526 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "conformance_test.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include "absl/strings/str_cat.h"
|
||||
#include "absl/strings/str_format.h"
|
||||
#include "conformance/conformance.pb.h"
|
||||
#include "google/protobuf/message.h"
|
||||
#include "google/protobuf/text_format.h"
|
||||
#include "google/protobuf/util/field_comparator.h"
|
||||
#include "google/protobuf/util/json_util.h"
|
||||
#include "google/protobuf/util/message_differencer.h"
|
||||
|
||||
using conformance::ConformanceRequest;
|
||||
using conformance::ConformanceResponse;
|
||||
using conformance::WireFormat;
|
||||
using google::protobuf::TextFormat;
|
||||
using google::protobuf::util::DefaultFieldComparator;
|
||||
using google::protobuf::util::MessageDifferencer;
|
||||
using std::string;
|
||||
|
||||
namespace {
|
||||
|
||||
static string ToOctString(const string& binary_string) {
|
||||
string oct_string;
|
||||
for (size_t i = 0; i < binary_string.size(); i++) {
|
||||
uint8_t c = binary_string.at(i);
|
||||
uint8_t high = c / 64;
|
||||
uint8_t mid = (c % 64) / 8;
|
||||
uint8_t low = c % 8;
|
||||
oct_string.push_back('\\');
|
||||
oct_string.push_back('0' + high);
|
||||
oct_string.push_back('0' + mid);
|
||||
oct_string.push_back('0' + low);
|
||||
}
|
||||
return oct_string;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
ConformanceTestSuite::ConformanceRequestSetting::ConformanceRequestSetting(
|
||||
ConformanceLevel level, conformance::WireFormat input_format,
|
||||
conformance::WireFormat output_format,
|
||||
conformance::TestCategory test_category, const Message& prototype_message,
|
||||
const string& test_name, const string& input)
|
||||
: level_(level),
|
||||
input_format_(input_format),
|
||||
output_format_(output_format),
|
||||
prototype_message_(prototype_message),
|
||||
prototype_message_for_compare_(prototype_message.New()),
|
||||
test_name_(test_name) {
|
||||
switch (input_format) {
|
||||
case conformance::PROTOBUF: {
|
||||
request_.set_protobuf_payload(input);
|
||||
break;
|
||||
}
|
||||
|
||||
case conformance::JSON: {
|
||||
request_.set_json_payload(input);
|
||||
break;
|
||||
}
|
||||
|
||||
case conformance::JSPB: {
|
||||
request_.set_jspb_payload(input);
|
||||
break;
|
||||
}
|
||||
|
||||
case conformance::TEXT_FORMAT: {
|
||||
request_.set_text_payload(input);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Unspecified input format";
|
||||
}
|
||||
|
||||
request_.set_test_category(test_category);
|
||||
|
||||
request_.set_message_type(prototype_message.GetDescriptor()->full_name());
|
||||
request_.set_requested_output_format(output_format);
|
||||
}
|
||||
|
||||
std::unique_ptr<Message>
|
||||
ConformanceTestSuite::ConformanceRequestSetting::NewTestMessage() const {
|
||||
return std::unique_ptr<Message>(prototype_message_for_compare_->New());
|
||||
}
|
||||
|
||||
string ConformanceTestSuite::ConformanceRequestSetting::GetTestName() const {
|
||||
string rname = prototype_message_.GetDescriptor()->file()->syntax() ==
|
||||
FileDescriptor::SYNTAX_PROTO3
|
||||
? "Proto3"
|
||||
: "Proto2";
|
||||
|
||||
return absl::StrCat(ConformanceLevelToString(level_), ".", rname, ".",
|
||||
InputFormatString(input_format_), ".", test_name_, ".",
|
||||
OutputFormatString(output_format_));
|
||||
}
|
||||
|
||||
string
|
||||
ConformanceTestSuite::ConformanceRequestSetting::ConformanceLevelToString(
|
||||
ConformanceLevel level) const {
|
||||
switch (level) {
|
||||
case REQUIRED:
|
||||
return "Required";
|
||||
case RECOMMENDED:
|
||||
return "Recommended";
|
||||
}
|
||||
GOOGLE_LOG(FATAL) << "Unknown value: " << level;
|
||||
return "";
|
||||
}
|
||||
|
||||
string ConformanceTestSuite::ConformanceRequestSetting::InputFormatString(
|
||||
conformance::WireFormat format) const {
|
||||
switch (format) {
|
||||
case conformance::PROTOBUF:
|
||||
return "ProtobufInput";
|
||||
case conformance::JSON:
|
||||
return "JsonInput";
|
||||
case conformance::TEXT_FORMAT:
|
||||
return "TextFormatInput";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Unspecified output format";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
string ConformanceTestSuite::ConformanceRequestSetting::OutputFormatString(
|
||||
conformance::WireFormat format) const {
|
||||
switch (format) {
|
||||
case conformance::PROTOBUF:
|
||||
return "ProtobufOutput";
|
||||
case conformance::JSON:
|
||||
return "JsonOutput";
|
||||
case conformance::TEXT_FORMAT:
|
||||
return "TextFormatOutput";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "Unspecified output format";
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::TruncateDebugPayload(string* payload) {
|
||||
if (payload != nullptr && payload->size() > 200) {
|
||||
payload->resize(200);
|
||||
payload->append("...(truncated)");
|
||||
}
|
||||
}
|
||||
|
||||
const ConformanceRequest ConformanceTestSuite::TruncateRequest(
|
||||
const ConformanceRequest& request) {
|
||||
ConformanceRequest debug_request(request);
|
||||
switch (debug_request.payload_case()) {
|
||||
case ConformanceRequest::kProtobufPayload:
|
||||
TruncateDebugPayload(debug_request.mutable_protobuf_payload());
|
||||
break;
|
||||
case ConformanceRequest::kJsonPayload:
|
||||
TruncateDebugPayload(debug_request.mutable_json_payload());
|
||||
break;
|
||||
case ConformanceRequest::kTextPayload:
|
||||
TruncateDebugPayload(debug_request.mutable_text_payload());
|
||||
break;
|
||||
case ConformanceRequest::kJspbPayload:
|
||||
TruncateDebugPayload(debug_request.mutable_jspb_payload());
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return debug_request;
|
||||
}
|
||||
|
||||
const ConformanceResponse ConformanceTestSuite::TruncateResponse(
|
||||
const ConformanceResponse& response) {
|
||||
ConformanceResponse debug_response(response);
|
||||
switch (debug_response.result_case()) {
|
||||
case ConformanceResponse::kProtobufPayload:
|
||||
TruncateDebugPayload(debug_response.mutable_protobuf_payload());
|
||||
break;
|
||||
case ConformanceResponse::kJsonPayload:
|
||||
TruncateDebugPayload(debug_response.mutable_json_payload());
|
||||
break;
|
||||
case ConformanceResponse::kTextPayload:
|
||||
TruncateDebugPayload(debug_response.mutable_text_payload());
|
||||
break;
|
||||
case ConformanceResponse::kJspbPayload:
|
||||
TruncateDebugPayload(debug_response.mutable_jspb_payload());
|
||||
break;
|
||||
default:
|
||||
// Do nothing.
|
||||
break;
|
||||
}
|
||||
return debug_response;
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::ReportSuccess(const string& test_name) {
|
||||
if (expected_to_fail_.erase(test_name) != 0) {
|
||||
absl::StrAppendFormat(
|
||||
&output_,
|
||||
"ERROR: test %s is in the failure list, but test succeeded. "
|
||||
"Remove it from the failure list.\n",
|
||||
test_name);
|
||||
unexpected_succeeding_tests_.insert(test_name);
|
||||
}
|
||||
successes_++;
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::ReportFailure(const string& test_name,
|
||||
ConformanceLevel level,
|
||||
const ConformanceRequest& request,
|
||||
const ConformanceResponse& response,
|
||||
std::string_view message) {
|
||||
if (expected_to_fail_.erase(test_name) == 1) {
|
||||
expected_failures_++;
|
||||
if (!verbose_)
|
||||
return;
|
||||
}
|
||||
else if (level == RECOMMENDED && !enforce_recommended_) {
|
||||
absl::StrAppendFormat(&output_, "WARNING, test=%s: ", test_name);
|
||||
}
|
||||
else {
|
||||
absl::StrAppendFormat(&output_, "ERROR, test=%s: ", test_name);
|
||||
unexpected_failing_tests_.insert(test_name);
|
||||
}
|
||||
|
||||
absl::StrAppendFormat(&output_, "%s, request=%s, response=%s\n", message,
|
||||
TruncateRequest(request).ShortDebugString(),
|
||||
TruncateResponse(response).ShortDebugString());
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::ReportSkip(const string& test_name,
|
||||
const ConformanceRequest& request,
|
||||
const ConformanceResponse& response) {
|
||||
if (verbose_) {
|
||||
absl::StrAppendFormat(
|
||||
&output_, "SKIPPED, test=%s request=%s, response=%s\n", test_name,
|
||||
request.ShortDebugString(), response.ShortDebugString());
|
||||
}
|
||||
skipped_.insert(test_name);
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::RunValidInputTest(
|
||||
const ConformanceRequestSetting& setting,
|
||||
const string& equivalent_text_format) {
|
||||
std::unique_ptr<Message> reference_message(setting.NewTestMessage());
|
||||
GOOGLE_CHECK(TextFormat::ParseFromString(equivalent_text_format,
|
||||
reference_message.get()))
|
||||
<< "Failed to parse data for test case: " << setting.GetTestName()
|
||||
<< ", data: " << equivalent_text_format;
|
||||
const string equivalent_wire_format = reference_message->SerializeAsString();
|
||||
RunValidBinaryInputTest(setting, equivalent_wire_format);
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::RunValidBinaryInputTest(
|
||||
const ConformanceRequestSetting& setting,
|
||||
const string& equivalent_wire_format, bool require_same_wire_format) {
|
||||
const ConformanceRequest& request = setting.GetRequest();
|
||||
ConformanceResponse response;
|
||||
RunTest(setting.GetTestName(), request, &response);
|
||||
VerifyResponse(setting, equivalent_wire_format, response, true,
|
||||
require_same_wire_format);
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::VerifyResponse(
|
||||
const ConformanceRequestSetting& setting,
|
||||
const string& equivalent_wire_format, const ConformanceResponse& response,
|
||||
bool need_report_success, bool require_same_wire_format) {
|
||||
std::unique_ptr<Message> test_message(setting.NewTestMessage());
|
||||
const ConformanceRequest& request = setting.GetRequest();
|
||||
const string& test_name = setting.GetTestName();
|
||||
ConformanceLevel level = setting.GetLevel();
|
||||
std::unique_ptr<Message> reference_message = setting.NewTestMessage();
|
||||
|
||||
GOOGLE_CHECK(reference_message->ParseFromString(equivalent_wire_format))
|
||||
<< "Failed to parse wire data for test case: " << test_name;
|
||||
|
||||
switch (response.result_case()) {
|
||||
case ConformanceResponse::RESULT_NOT_SET:
|
||||
ReportFailure(test_name, level, request, response,
|
||||
"Response didn't have any field in the Response.");
|
||||
return;
|
||||
|
||||
case ConformanceResponse::kParseError:
|
||||
case ConformanceResponse::kTimeoutError:
|
||||
case ConformanceResponse::kRuntimeError:
|
||||
case ConformanceResponse::kSerializeError:
|
||||
ReportFailure(test_name, level, request, response,
|
||||
"Failed to parse input or produce output.");
|
||||
return;
|
||||
|
||||
case ConformanceResponse::kSkipped:
|
||||
ReportSkip(test_name, request, response);
|
||||
return;
|
||||
|
||||
default:
|
||||
if (!ParseResponse(response, setting, test_message.get()))
|
||||
return;
|
||||
}
|
||||
|
||||
MessageDifferencer differencer;
|
||||
DefaultFieldComparator field_comparator;
|
||||
field_comparator.set_treat_nan_as_equal(true);
|
||||
differencer.set_field_comparator(&field_comparator);
|
||||
string differences;
|
||||
differencer.ReportDifferencesToString(&differences);
|
||||
|
||||
bool check = false;
|
||||
|
||||
if (require_same_wire_format) {
|
||||
GOOGLE_DCHECK_EQ(response.result_case(),
|
||||
ConformanceResponse::kProtobufPayload);
|
||||
const string& protobuf_payload = response.protobuf_payload();
|
||||
check = equivalent_wire_format == protobuf_payload;
|
||||
differences = absl::StrCat("Expect: ", ToOctString(equivalent_wire_format),
|
||||
", but got: ", ToOctString(protobuf_payload));
|
||||
}
|
||||
else {
|
||||
check = differencer.Compare(*reference_message, *test_message);
|
||||
}
|
||||
|
||||
if (check) {
|
||||
if (need_report_success) {
|
||||
ReportSuccess(test_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
ReportFailure(
|
||||
test_name, level, request, response,
|
||||
absl::StrCat("Output was not equivalent to reference message: ",
|
||||
differences));
|
||||
}
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::RunTest(const string& test_name,
|
||||
const ConformanceRequest& request,
|
||||
ConformanceResponse* response) {
|
||||
if (test_names_.insert(test_name).second == false) {
|
||||
GOOGLE_LOG(FATAL) << "Duplicated test name: " << test_name;
|
||||
}
|
||||
|
||||
string serialized_request;
|
||||
string serialized_response;
|
||||
request.SerializeToString(&serialized_request);
|
||||
|
||||
runner_->RunTest(test_name, serialized_request, &serialized_response);
|
||||
|
||||
if (!response->ParseFromString(serialized_response)) {
|
||||
response->Clear();
|
||||
response->set_runtime_error("response proto could not be parsed.");
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
absl::StrAppendFormat(
|
||||
&output_, "conformance test: name=%s, request=%s, response=%s\n",
|
||||
test_name, TruncateRequest(request).ShortDebugString(),
|
||||
TruncateResponse(*response).ShortDebugString());
|
||||
}
|
||||
}
|
||||
|
||||
bool ConformanceTestSuite::CheckSetEmpty(const std::set<string>& set_to_check,
|
||||
const std::string& write_to_file,
|
||||
const std::string& msg) {
|
||||
if (set_to_check.empty()) {
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
absl::StrAppendFormat(&output_, "\n");
|
||||
absl::StrAppendFormat(&output_, "%s\n\n", msg);
|
||||
for (std::string_view v : set_to_check) {
|
||||
absl::StrAppendFormat(&output_, " %s\n", v);
|
||||
}
|
||||
absl::StrAppendFormat(&output_, "\n");
|
||||
|
||||
if (!write_to_file.empty()) {
|
||||
std::string full_filename;
|
||||
const std::string* filename = &write_to_file;
|
||||
if (!output_dir_.empty()) {
|
||||
full_filename = output_dir_;
|
||||
if (*output_dir_.rbegin() != '/') {
|
||||
full_filename.push_back('/');
|
||||
}
|
||||
full_filename += write_to_file;
|
||||
filename = &full_filename;
|
||||
}
|
||||
std::ofstream os(*filename);
|
||||
if (os) {
|
||||
for (std::string_view v : set_to_check) {
|
||||
os << v << "\n";
|
||||
}
|
||||
}
|
||||
else {
|
||||
absl::StrAppendFormat(&output_, "Failed to open file: %s\n", *filename);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
string ConformanceTestSuite::WireFormatToString(WireFormat wire_format) {
|
||||
switch (wire_format) {
|
||||
case conformance::PROTOBUF:
|
||||
return "PROTOBUF";
|
||||
case conformance::JSON:
|
||||
return "JSON";
|
||||
case conformance::JSPB:
|
||||
return "JSPB";
|
||||
case conformance::TEXT_FORMAT:
|
||||
return "TEXT_FORMAT";
|
||||
case conformance::UNSPECIFIED:
|
||||
return "UNSPECIFIED";
|
||||
default:
|
||||
GOOGLE_LOG(FATAL) << "unknown wire type: " << wire_format;
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
void ConformanceTestSuite::AddExpectedFailedTest(const std::string& test_name) {
|
||||
expected_to_fail_.insert(test_name);
|
||||
}
|
||||
|
||||
bool ConformanceTestSuite::RunSuite(ConformanceTestRunner* runner,
|
||||
std::string* output, const string& filename,
|
||||
conformance::FailureSet* failure_list) {
|
||||
runner_ = runner;
|
||||
successes_ = 0;
|
||||
expected_failures_ = 0;
|
||||
skipped_.clear();
|
||||
test_names_.clear();
|
||||
unexpected_failing_tests_.clear();
|
||||
unexpected_succeeding_tests_.clear();
|
||||
|
||||
output_ = "\nCONFORMANCE TEST BEGIN ====================================\n\n";
|
||||
|
||||
failure_list_filename_ = filename;
|
||||
expected_to_fail_.clear();
|
||||
for (const string& failure : failure_list->failure()) {
|
||||
AddExpectedFailedTest(failure);
|
||||
}
|
||||
RunSuiteImpl();
|
||||
|
||||
bool ok = true;
|
||||
if (!CheckSetEmpty(expected_to_fail_, "nonexistent_tests.txt",
|
||||
"These tests were listed in the failure list, but they "
|
||||
"don't exist. Remove them from the failure list by "
|
||||
"running:\n"
|
||||
" ./update_failure_list.py " +
|
||||
failure_list_filename_ +
|
||||
" --remove nonexistent_tests.txt")) {
|
||||
ok = false;
|
||||
}
|
||||
if (!CheckSetEmpty(unexpected_failing_tests_, "failing_tests.txt",
|
||||
"These tests failed. If they can't be fixed right now, "
|
||||
"you can add them to the failure list so the overall "
|
||||
"suite can succeed. Add them to the failure list by "
|
||||
"running:\n"
|
||||
" ./update_failure_list.py " +
|
||||
failure_list_filename_ + " --add failing_tests.txt")) {
|
||||
ok = false;
|
||||
}
|
||||
if (!CheckSetEmpty(unexpected_succeeding_tests_, "succeeding_tests.txt",
|
||||
"These tests succeeded, even though they were listed in "
|
||||
"the failure list. Remove them from the failure list "
|
||||
"by running:\n"
|
||||
" ./update_failure_list.py " +
|
||||
failure_list_filename_ +
|
||||
" --remove succeeding_tests.txt")) {
|
||||
ok = false;
|
||||
}
|
||||
|
||||
if (verbose_) {
|
||||
CheckSetEmpty(skipped_, "",
|
||||
"These tests were skipped (probably because support for some "
|
||||
"features is not implemented)");
|
||||
}
|
||||
|
||||
absl::StrAppendFormat(&output_,
|
||||
"CONFORMANCE SUITE %s: %d successes, %zu skipped, "
|
||||
"%d expected failures, %zu unexpected failures.\n",
|
||||
ok ? "PASSED" : "FAILED", successes_, skipped_.size(),
|
||||
expected_failures_, unexpected_failing_tests_.size());
|
||||
absl::StrAppendFormat(&output_, "\n");
|
||||
|
||||
output->assign(output_);
|
||||
|
||||
return ok;
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
|
@ -1,331 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file defines a protocol for running the conformance test suite
|
||||
// in-process. In other words, the suite itself will run in the same process as
|
||||
// the code under test.
|
||||
//
|
||||
// For pros and cons of this approach, please see conformance.proto.
|
||||
|
||||
#ifndef CONFORMANCE_CONFORMANCE_TEST_H
|
||||
#define CONFORMANCE_CONFORMANCE_TEST_H
|
||||
|
||||
#include <functional>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "conformance/conformance.pb.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/util/type_resolver.h"
|
||||
#include "google/protobuf/wire_format_lite.h"
|
||||
|
||||
namespace conformance {
|
||||
class ConformanceRequest;
|
||||
class ConformanceResponse;
|
||||
} // namespace conformance
|
||||
|
||||
namespace protobuf_test_messages {
|
||||
namespace proto3 {
|
||||
class TestAllTypesProto3;
|
||||
} // namespace proto3
|
||||
} // namespace protobuf_test_messages
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
class ConformanceTestSuite;
|
||||
|
||||
class ConformanceTestRunner {
|
||||
public:
|
||||
virtual ~ConformanceTestRunner() {}
|
||||
|
||||
// Call to run a single conformance test.
|
||||
//
|
||||
// "input" is a serialized conformance.ConformanceRequest.
|
||||
// "output" should be set to a serialized conformance.ConformanceResponse.
|
||||
//
|
||||
// If there is any error in running the test itself, set "runtime_error" in
|
||||
// the response.
|
||||
virtual void RunTest(const std::string& test_name, const std::string& input,
|
||||
std::string* output) = 0;
|
||||
};
|
||||
|
||||
// Test runner that spawns the process being tested and communicates with it
|
||||
// over a pipe.
|
||||
class ForkPipeRunner : public ConformanceTestRunner {
|
||||
public:
|
||||
// Note: Run() doesn't take ownership of the pointers inside suites.
|
||||
static int Run(int argc, char* argv[],
|
||||
const std::vector<ConformanceTestSuite*>& suites);
|
||||
|
||||
ForkPipeRunner(const std::string& executable,
|
||||
const std::vector<std::string>& executable_args,
|
||||
bool performance)
|
||||
: child_pid_(-1),
|
||||
executable_(executable),
|
||||
executable_args_(executable_args),
|
||||
performance_(performance) {}
|
||||
|
||||
explicit ForkPipeRunner(const std::string& executable)
|
||||
: child_pid_(-1), executable_(executable) {}
|
||||
|
||||
virtual ~ForkPipeRunner() {}
|
||||
|
||||
void RunTest(const std::string& test_name, const std::string& request,
|
||||
std::string* response);
|
||||
|
||||
private:
|
||||
void SpawnTestProgram();
|
||||
|
||||
void CheckedWrite(int fd, const void* buf, size_t len);
|
||||
bool TryRead(int fd, void* buf, size_t len);
|
||||
void CheckedRead(int fd, void* buf, size_t len);
|
||||
|
||||
int write_fd_;
|
||||
int read_fd_;
|
||||
pid_t child_pid_;
|
||||
std::string executable_;
|
||||
const std::vector<std::string> executable_args_;
|
||||
bool performance_;
|
||||
std::string current_test_name_;
|
||||
};
|
||||
|
||||
// Class representing the test suite itself. To run it, implement your own
|
||||
// class derived from ConformanceTestRunner, class derived from
|
||||
// ConformanceTestSuite and then write code like:
|
||||
//
|
||||
// class MyConformanceTestSuite : public ConformanceTestSuite {
|
||||
// public:
|
||||
// void RunSuiteImpl() {
|
||||
// // INSERT ACTUAL TESTS.
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// class MyConformanceTestRunner : public ConformanceTestRunner {
|
||||
// public:
|
||||
// static int Run(int argc, char *argv[],
|
||||
// ConformanceTestSuite* suite);
|
||||
//
|
||||
// private:
|
||||
// virtual void RunTest(...) {
|
||||
// // INSERT YOUR FRAMEWORK-SPECIFIC CODE HERE.
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// int main() {
|
||||
// MyConformanceTestSuite suite;
|
||||
// MyConformanceTestRunner::Run(argc, argv, &suite);
|
||||
// }
|
||||
//
|
||||
class ConformanceTestSuite {
|
||||
public:
|
||||
ConformanceTestSuite()
|
||||
: verbose_(false),
|
||||
performance_(false),
|
||||
enforce_recommended_(false),
|
||||
failure_list_flag_name_("--failure_list") {}
|
||||
virtual ~ConformanceTestSuite() {}
|
||||
|
||||
void SetPerformance(bool performance) { performance_ = performance; }
|
||||
void SetVerbose(bool verbose) { verbose_ = verbose; }
|
||||
|
||||
// Whether to require the testee to pass RECOMMENDED tests. By default failing
|
||||
// a RECOMMENDED test case will not fail the entire suite but will only
|
||||
// generated a warning. If this flag is set to true, RECOMMENDED tests will
|
||||
// be treated the same way as REQUIRED tests and failing a RECOMMENDED test
|
||||
// case will cause the entire test suite to fail as well. An implementation
|
||||
// can enable this if it wants to be strictly conforming to protobuf spec.
|
||||
// See the comments about ConformanceLevel below to learn more about the
|
||||
// difference between REQUIRED and RECOMMENDED test cases.
|
||||
void SetEnforceRecommended(bool value) { enforce_recommended_ = value; }
|
||||
|
||||
// Gets the flag name to the failure list file.
|
||||
// By default, this would return --failure_list
|
||||
std::string GetFailureListFlagName() { return failure_list_flag_name_; }
|
||||
|
||||
void SetFailureListFlagName(const std::string& failure_list_flag_name) {
|
||||
failure_list_flag_name_ = failure_list_flag_name;
|
||||
}
|
||||
|
||||
// Sets the path of the output directory.
|
||||
void SetOutputDir(const char* output_dir) { output_dir_ = output_dir; }
|
||||
|
||||
// Run all the conformance tests against the given test runner.
|
||||
// Test output will be stored in "output".
|
||||
//
|
||||
// Returns true if the set of failing tests was exactly the same as the
|
||||
// failure list.
|
||||
// The filename here is *only* used to create/format useful error messages for
|
||||
// how to update the failure list. We do NOT read this file at all.
|
||||
bool RunSuite(ConformanceTestRunner* runner, std::string* output,
|
||||
const std::string& filename,
|
||||
conformance::FailureSet* failure_list);
|
||||
|
||||
protected:
|
||||
// Test cases are classified into a few categories:
|
||||
// REQUIRED: the test case must be passed for an implementation to be
|
||||
// interoperable with other implementations. For example, a
|
||||
// parser implementation must accept both packed and unpacked
|
||||
// form of repeated primitive fields.
|
||||
// RECOMMENDED: the test case is not required for the implementation to
|
||||
// be interoperable with other implementations, but is
|
||||
// recommended for best performance and compatibility. For
|
||||
// example, a proto3 serializer should serialize repeated
|
||||
// primitive fields in packed form, but an implementation
|
||||
// failing to do so will still be able to communicate with
|
||||
// other implementations.
|
||||
enum ConformanceLevel {
|
||||
REQUIRED = 0,
|
||||
RECOMMENDED = 1,
|
||||
};
|
||||
|
||||
class ConformanceRequestSetting {
|
||||
public:
|
||||
ConformanceRequestSetting(ConformanceLevel level,
|
||||
conformance::WireFormat input_format,
|
||||
conformance::WireFormat output_format,
|
||||
conformance::TestCategory test_category,
|
||||
const Message& prototype_message,
|
||||
const std::string& test_name,
|
||||
const std::string& input);
|
||||
virtual ~ConformanceRequestSetting() {}
|
||||
|
||||
std::unique_ptr<Message> NewTestMessage() const;
|
||||
|
||||
std::string GetTestName() const;
|
||||
|
||||
const conformance::ConformanceRequest& GetRequest() const {
|
||||
return request_;
|
||||
}
|
||||
|
||||
const ConformanceLevel GetLevel() const { return level_; }
|
||||
|
||||
std::string ConformanceLevelToString(ConformanceLevel level) const;
|
||||
|
||||
void SetPrintUnknownFields(bool print_unknown_fields) {
|
||||
request_.set_print_unknown_fields(true);
|
||||
}
|
||||
|
||||
void SetPrototypeMessageForCompare(const Message& message) {
|
||||
prototype_message_for_compare_.reset(message.New());
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual std::string InputFormatString(conformance::WireFormat format) const;
|
||||
virtual std::string OutputFormatString(
|
||||
conformance::WireFormat format) const;
|
||||
conformance::ConformanceRequest request_;
|
||||
|
||||
private:
|
||||
ConformanceLevel level_;
|
||||
::conformance::WireFormat input_format_;
|
||||
::conformance::WireFormat output_format_;
|
||||
const Message& prototype_message_;
|
||||
std::unique_ptr<Message> prototype_message_for_compare_;
|
||||
std::string test_name_;
|
||||
};
|
||||
|
||||
bool CheckSetEmpty(const std::set<std::string>& set_to_check,
|
||||
const std::string& write_to_file, const std::string& msg);
|
||||
std::string WireFormatToString(conformance::WireFormat wire_format);
|
||||
|
||||
// Parse payload in the response to the given message. Returns true on
|
||||
// success.
|
||||
virtual bool ParseResponse(const conformance::ConformanceResponse& response,
|
||||
const ConformanceRequestSetting& setting,
|
||||
Message* test_message) = 0;
|
||||
|
||||
void VerifyResponse(const ConformanceRequestSetting& setting,
|
||||
const std::string& equivalent_wire_format,
|
||||
const conformance::ConformanceResponse& response,
|
||||
bool need_report_success, bool require_same_wire_format);
|
||||
|
||||
void TruncateDebugPayload(std::string* payload);
|
||||
const conformance::ConformanceRequest TruncateRequest(
|
||||
const conformance::ConformanceRequest& request);
|
||||
const conformance::ConformanceResponse TruncateResponse(
|
||||
const conformance::ConformanceResponse& response);
|
||||
|
||||
void ReportSuccess(const std::string& test_name);
|
||||
void ReportFailure(const std::string& test_name, ConformanceLevel level,
|
||||
const conformance::ConformanceRequest& request,
|
||||
const conformance::ConformanceResponse& response,
|
||||
std::string_view message);
|
||||
void ReportSkip(const std::string& test_name,
|
||||
const conformance::ConformanceRequest& request,
|
||||
const conformance::ConformanceResponse& response);
|
||||
|
||||
void RunValidInputTest(const ConformanceRequestSetting& setting,
|
||||
const std::string& equivalent_text_format);
|
||||
void RunValidBinaryInputTest(const ConformanceRequestSetting& setting,
|
||||
const std::string& equivalent_wire_format,
|
||||
bool require_same_wire_format = false);
|
||||
|
||||
void RunTest(const std::string& test_name,
|
||||
const conformance::ConformanceRequest& request,
|
||||
conformance::ConformanceResponse* response);
|
||||
|
||||
void AddExpectedFailedTest(const std::string& test_name);
|
||||
|
||||
virtual void RunSuiteImpl() = 0;
|
||||
|
||||
ConformanceTestRunner* runner_;
|
||||
int successes_;
|
||||
int expected_failures_;
|
||||
bool verbose_;
|
||||
bool performance_;
|
||||
bool enforce_recommended_;
|
||||
std::string output_;
|
||||
std::string output_dir_;
|
||||
std::string failure_list_flag_name_;
|
||||
std::string failure_list_filename_;
|
||||
|
||||
// The set of test names that are expected to fail in this run, but haven't
|
||||
// failed yet.
|
||||
std::set<std::string> expected_to_fail_;
|
||||
|
||||
// The set of test names that have been run. Used to ensure that there are no
|
||||
// duplicate names in the suite.
|
||||
std::set<std::string> test_names_;
|
||||
|
||||
// The set of tests that failed, but weren't expected to.
|
||||
std::set<std::string> unexpected_failing_tests_;
|
||||
|
||||
// The set of tests that succeeded, but weren't expected to.
|
||||
std::set<std::string> unexpected_succeeding_tests_;
|
||||
|
||||
// The set of tests that the testee opted out of;
|
||||
std::set<std::string> skipped_;
|
||||
};
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
||||
#endif // CONFORMANCE_CONFORMANCE_TEST_H
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
#include "binary_json_conformance_suite.h"
|
||||
#include "conformance_test.h"
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
google::protobuf::BinaryAndJsonConformanceSuite binary_and_json_suite;
|
||||
return google::protobuf::ForkPipeRunner::Run(argc, argv,
|
||||
{&binary_and_json_suite});
|
||||
}
|
||||
|
|
@ -1,407 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// This file contains a program for running the test suite in a separate
|
||||
// process. The other alternative is to run the suite in-process. See
|
||||
// conformance.proto for pros/cons of these two options.
|
||||
//
|
||||
// This program will fork the process under test and communicate with it over
|
||||
// its stdin/stdout:
|
||||
//
|
||||
// +--------+ pipe +----------+
|
||||
// | tester | <------> | testee |
|
||||
// | | | |
|
||||
// | C++ | | any lang |
|
||||
// +--------+ +----------+
|
||||
//
|
||||
// The tester contains all of the test cases and their expected output.
|
||||
// The testee is a simple program written in the target language that reads
|
||||
// each test case and attempts to produce acceptable output for it.
|
||||
//
|
||||
// Every test consists of a ConformanceRequest/ConformanceResponse
|
||||
// request/reply pair. The protocol on the pipe is simply:
|
||||
//
|
||||
// 1. tester sends 4-byte length N (little endian)
|
||||
// 2. tester sends N bytes representing a ConformanceRequest proto
|
||||
// 3. testee sends 4-byte length M (little endian)
|
||||
// 4. testee sends M bytes representing a ConformanceResponse proto
|
||||
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstdlib>
|
||||
#include <fstream>
|
||||
#include <future>
|
||||
#include <vector>
|
||||
|
||||
// #include "absl/strings/str_format.h"
|
||||
#include "conformance/conformance.pb.h"
|
||||
#include "conformance_test.h"
|
||||
|
||||
using conformance::ConformanceResponse;
|
||||
using google::protobuf::ConformanceTestSuite;
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#define STRINGIFY(x) #x
|
||||
#define TOSTRING(x) STRINGIFY(x)
|
||||
#define GOOGLE_CHECK_SYSCALL(call) \
|
||||
if (call < 0) { \
|
||||
perror(#call " " __FILE__ ":" TOSTRING(__LINE__)); \
|
||||
exit(1); \
|
||||
}
|
||||
|
||||
namespace google {
|
||||
namespace protobuf {
|
||||
|
||||
void ParseFailureList(const char *filename,
|
||||
conformance::FailureSet *failure_list) {
|
||||
std::ifstream infile(filename);
|
||||
|
||||
if (!infile.is_open()) {
|
||||
fprintf(stderr, "Couldn't open failure list file: %s\n", filename);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
for (string line; getline(infile, line);) {
|
||||
// Remove whitespace.
|
||||
line.erase(std::remove_if(line.begin(), line.end(), ::isspace), line.end());
|
||||
|
||||
// Remove comments.
|
||||
line = line.substr(0, line.find("#"));
|
||||
|
||||
if (!line.empty()) {
|
||||
failure_list->add_failure(line);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UsageError() {
|
||||
fprintf(stderr, "Usage: conformance-test-runner [options] <test-program>\n");
|
||||
fprintf(stderr, "\n");
|
||||
fprintf(stderr, "Options:\n");
|
||||
fprintf(stderr,
|
||||
" --failure_list <filename> Use to specify list of tests\n");
|
||||
fprintf(stderr,
|
||||
" that are expected to fail. File\n");
|
||||
fprintf(stderr,
|
||||
" should contain one test name per\n");
|
||||
fprintf(stderr,
|
||||
" line. Use '#' for comments.\n");
|
||||
fprintf(stderr,
|
||||
" --text_format_failure_list <filename> Use to specify list \n");
|
||||
fprintf(stderr,
|
||||
" of tests that are expected to \n");
|
||||
fprintf(stderr, " fail in the \n");
|
||||
fprintf(stderr,
|
||||
" text_format_conformance_suite. \n");
|
||||
fprintf(stderr,
|
||||
" File should contain one test name \n");
|
||||
fprintf(stderr,
|
||||
" per line. Use '#' for comments.\n");
|
||||
|
||||
fprintf(stderr,
|
||||
" --enforce_recommended Enforce that recommended test\n");
|
||||
fprintf(stderr,
|
||||
" cases are also passing. Specify\n");
|
||||
fprintf(stderr,
|
||||
" this flag if you want to be\n");
|
||||
fprintf(stderr,
|
||||
" strictly conforming to protobuf\n");
|
||||
fprintf(stderr, " spec.\n");
|
||||
fprintf(stderr,
|
||||
" --output_dir <dirname> Directory to write\n"
|
||||
" output files.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void ForkPipeRunner::RunTest(const std::string &test_name,
|
||||
const std::string &request,
|
||||
std::string *response) {
|
||||
if (child_pid_ < 0) {
|
||||
SpawnTestProgram();
|
||||
}
|
||||
current_test_name_ = test_name;
|
||||
|
||||
uint32_t len = request.size();
|
||||
CheckedWrite(write_fd_, &len, sizeof(uint32_t));
|
||||
CheckedWrite(write_fd_, request.c_str(), request.size());
|
||||
|
||||
if (!TryRead(read_fd_, &len, sizeof(uint32_t))) {
|
||||
// We failed to read from the child, assume a crash and try to reap.
|
||||
GOOGLE_LOG(INFO) << "Trying to reap child, pid=" << child_pid_;
|
||||
|
||||
int status = 0;
|
||||
waitpid(child_pid_, &status, WEXITED);
|
||||
|
||||
string error_msg;
|
||||
conformance::ConformanceResponse response_obj;
|
||||
if (WIFEXITED(status)) {
|
||||
if (WEXITSTATUS(status) == 0) {
|
||||
error_msg = "child timed out, killed by signal " +
|
||||
std::to_string(WTERMSIG(status));
|
||||
response_obj.set_timeout_error(error_msg);
|
||||
}
|
||||
else {
|
||||
error_msg =
|
||||
"child exited, status=" + std::to_string(WEXITSTATUS(status));
|
||||
response_obj.set_runtime_error(error_msg);
|
||||
}
|
||||
}
|
||||
else if (WIFSIGNALED(status)) {
|
||||
error_msg = "child killed by signal " + std::to_string(WTERMSIG(status));
|
||||
}
|
||||
GOOGLE_LOG(INFO) << error_msg;
|
||||
child_pid_ = -1;
|
||||
|
||||
response_obj.SerializeToString(response);
|
||||
return;
|
||||
}
|
||||
|
||||
response->resize(len);
|
||||
CheckedRead(read_fd_, (void *)response->c_str(), len);
|
||||
}
|
||||
|
||||
int ForkPipeRunner::Run(int argc, char *argv[],
|
||||
const std::vector<ConformanceTestSuite *> &suites) {
|
||||
if (suites.empty()) {
|
||||
fprintf(stderr, "No test suites found.\n");
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
bool all_ok = true;
|
||||
for (ConformanceTestSuite *suite : suites) {
|
||||
string program;
|
||||
std::vector<string> program_args;
|
||||
string failure_list_filename;
|
||||
conformance::FailureSet failure_list;
|
||||
|
||||
bool performance = false;
|
||||
for (int arg = 1; arg < argc; ++arg) {
|
||||
if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) {
|
||||
if (++arg == argc)
|
||||
UsageError();
|
||||
failure_list_filename = argv[arg];
|
||||
ParseFailureList(argv[arg], &failure_list);
|
||||
}
|
||||
else if (strcmp(argv[arg], "--performance") == 0) {
|
||||
performance = true;
|
||||
suite->SetPerformance(true);
|
||||
}
|
||||
else if (strcmp(argv[arg], "--verbose") == 0) {
|
||||
suite->SetVerbose(true);
|
||||
}
|
||||
else if (strcmp(argv[arg], "--enforce_recommended") == 0) {
|
||||
suite->SetEnforceRecommended(true);
|
||||
}
|
||||
else if (strcmp(argv[arg], "--output_dir") == 0) {
|
||||
if (++arg == argc)
|
||||
UsageError();
|
||||
suite->SetOutputDir(argv[arg]);
|
||||
}
|
||||
else if (argv[arg][0] == '-') {
|
||||
bool recognized_flag = false;
|
||||
for (ConformanceTestSuite *suite : suites) {
|
||||
if (strcmp(argv[arg], suite->GetFailureListFlagName().c_str()) == 0) {
|
||||
if (++arg == argc)
|
||||
UsageError();
|
||||
recognized_flag = true;
|
||||
}
|
||||
}
|
||||
if (!recognized_flag) {
|
||||
fprintf(stderr, "Unknown option: %s\n", argv[arg]);
|
||||
UsageError();
|
||||
}
|
||||
}
|
||||
else {
|
||||
program += argv[arg++];
|
||||
while (arg < argc) {
|
||||
program_args.push_back(argv[arg]);
|
||||
arg++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ForkPipeRunner runner(program, program_args, performance);
|
||||
|
||||
std::string output;
|
||||
all_ok = all_ok && suite->RunSuite(&runner, &output, failure_list_filename,
|
||||
&failure_list);
|
||||
|
||||
fwrite(output.c_str(), 1, output.size(), stderr);
|
||||
}
|
||||
return all_ok ? EXIT_SUCCESS : EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// TODO(haberman): make this work on Windows, instead of using these
|
||||
// UNIX-specific APIs.
|
||||
//
|
||||
// There is a platform-agnostic API in
|
||||
// src/google/protobuf/compiler/subprocess.h
|
||||
//
|
||||
// However that API only supports sending a single message to the subprocess.
|
||||
// We really want to be able to send messages and receive responses one at a
|
||||
// time:
|
||||
//
|
||||
// 1. Spawning a new process for each test would take way too long for thousands
|
||||
// of tests and subprocesses like java that can take 100ms or more to start
|
||||
// up.
|
||||
//
|
||||
// 2. Sending all the tests in one big message and receiving all results in one
|
||||
// big message would take away our visibility about which test(s) caused a
|
||||
// crash or other fatal error. It would also give us only a single failure
|
||||
// instead of all of them.
|
||||
void ForkPipeRunner::SpawnTestProgram() {
|
||||
int toproc_pipe_fd[2];
|
||||
int fromproc_pipe_fd[2];
|
||||
if (pipe(toproc_pipe_fd) < 0 || pipe(fromproc_pipe_fd) < 0) {
|
||||
perror("pipe");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid < 0) {
|
||||
perror("fork");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (pid) {
|
||||
// Parent.
|
||||
GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0]));
|
||||
GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1]));
|
||||
write_fd_ = toproc_pipe_fd[1];
|
||||
read_fd_ = fromproc_pipe_fd[0];
|
||||
child_pid_ = pid;
|
||||
}
|
||||
else {
|
||||
// Child.
|
||||
GOOGLE_CHECK_SYSCALL(close(STDIN_FILENO));
|
||||
GOOGLE_CHECK_SYSCALL(close(STDOUT_FILENO));
|
||||
GOOGLE_CHECK_SYSCALL(dup2(toproc_pipe_fd[0], STDIN_FILENO));
|
||||
GOOGLE_CHECK_SYSCALL(dup2(fromproc_pipe_fd[1], STDOUT_FILENO));
|
||||
|
||||
GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[0]));
|
||||
GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[1]));
|
||||
GOOGLE_CHECK_SYSCALL(close(toproc_pipe_fd[1]));
|
||||
GOOGLE_CHECK_SYSCALL(close(fromproc_pipe_fd[0]));
|
||||
|
||||
std::unique_ptr<char[]> executable(new char[executable_.size() + 1]);
|
||||
memcpy(executable.get(), executable_.c_str(), executable_.size());
|
||||
executable[executable_.size()] = '\0';
|
||||
|
||||
std::vector<const char *> argv;
|
||||
argv.push_back(executable.get());
|
||||
GOOGLE_LOG(INFO) << argv[0];
|
||||
for (size_t i = 0; i < executable_args_.size(); ++i) {
|
||||
argv.push_back(executable_args_[i].c_str());
|
||||
GOOGLE_LOG(INFO) << executable_args_[i];
|
||||
}
|
||||
argv.push_back(nullptr);
|
||||
// Never returns.
|
||||
GOOGLE_CHECK_SYSCALL(
|
||||
execv(executable.get(), const_cast<char **>(argv.data())));
|
||||
}
|
||||
}
|
||||
|
||||
void ForkPipeRunner::CheckedWrite(int fd, const void *buf, size_t len) {
|
||||
if (static_cast<size_t>(write(fd, buf, len)) != len) {
|
||||
GOOGLE_LOG(FATAL) << current_test_name_
|
||||
<< ": error writing to test program: " << strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
bool ForkPipeRunner::TryRead(int fd, void *buf, size_t len) {
|
||||
size_t ofs = 0;
|
||||
while (len > 0) {
|
||||
std::future<ssize_t> future = std::async(
|
||||
std::launch::async,
|
||||
[](int fd, void *buf, size_t ofs, size_t len) {
|
||||
return read(fd, (char *)buf + ofs, len);
|
||||
},
|
||||
fd, buf, ofs, len);
|
||||
std::future_status status;
|
||||
if (performance_) {
|
||||
status = future.wait_for(std::chrono::seconds(5));
|
||||
if (status == std::future_status::timeout) {
|
||||
GOOGLE_LOG(ERROR) << current_test_name_
|
||||
<< ": timeout from test program";
|
||||
kill(child_pid_, SIGQUIT);
|
||||
// TODO(sandyzhang): Only log in flag-guarded mode, since reading output
|
||||
// from SIGQUIT is slow and verbose.
|
||||
std::vector<char> err;
|
||||
err.resize(5000);
|
||||
ssize_t err_bytes_read;
|
||||
size_t err_ofs = 0;
|
||||
do {
|
||||
err_bytes_read =
|
||||
read(fd, (void *)&err[err_ofs], err.size() - err_ofs);
|
||||
err_ofs += err_bytes_read;
|
||||
} while (err_bytes_read > 0 && err_ofs < err.size());
|
||||
GOOGLE_LOG(ERROR) << "child_pid_=" << child_pid_ << " SIGQUIT: \n"
|
||||
<< &err[0];
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
future.wait();
|
||||
}
|
||||
ssize_t bytes_read = future.get();
|
||||
if (bytes_read == 0) {
|
||||
GOOGLE_LOG(ERROR) << current_test_name_
|
||||
<< ": unexpected EOF from test program";
|
||||
return false;
|
||||
}
|
||||
else if (bytes_read < 0) {
|
||||
GOOGLE_LOG(ERROR) << current_test_name_
|
||||
<< ": error reading from test program: "
|
||||
<< strerror(errno);
|
||||
return false;
|
||||
}
|
||||
|
||||
len -= bytes_read;
|
||||
ofs += bytes_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ForkPipeRunner::CheckedRead(int fd, void *buf, size_t len) {
|
||||
if (!TryRead(fd, buf, len)) {
|
||||
GOOGLE_LOG(FATAL) << current_test_name_
|
||||
<< ": error reading from test program: "
|
||||
<< strerror(errno);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace protobuf
|
||||
} // namespace google
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
# This is the list of conformance tests that are known to fail for the C++
|
||||
# implementation right now. These should be fixed.
|
||||
#
|
||||
# By listing them here we can keep tabs on which ones are failing and be sure
|
||||
# that we don't introduce regressions in other tests.
|
||||
#
|
||||
# TODO(haberman): insert links to corresponding bugs tracking the issue.
|
||||
# Should we use GitHub issues or the Google-internal bug tracker?
|
||||
|
||||
|
|
@ -1,161 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/types/known/anypb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "AnyProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
|
||||
// `Any` contains an arbitrary serialized protocol buffer message along with a
|
||||
// URL that describes the type of the serialized message.
|
||||
//
|
||||
// Protobuf library provides support to pack/unpack Any values in the form
|
||||
// of utility functions or additional generated methods of the Any type.
|
||||
//
|
||||
// Example 1: Pack and unpack a message in C++.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any;
|
||||
// any.PackFrom(foo);
|
||||
// ...
|
||||
// if (any.UnpackTo(&foo)) {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// Example 2: Pack and unpack a message in Java.
|
||||
//
|
||||
// Foo foo = ...;
|
||||
// Any any = Any.pack(foo);
|
||||
// ...
|
||||
// if (any.is(Foo.class)) {
|
||||
// foo = any.unpack(Foo.class);
|
||||
// }
|
||||
// // or ...
|
||||
// if (any.isSameTypeAs(Foo.getDefaultInstance())) {
|
||||
// foo = any.unpack(Foo.getDefaultInstance());
|
||||
// }
|
||||
//
|
||||
// Example 3: Pack and unpack a message in Python.
|
||||
//
|
||||
// foo = Foo(...)
|
||||
// any = Any()
|
||||
// any.Pack(foo)
|
||||
// ...
|
||||
// if any.Is(Foo.DESCRIPTOR):
|
||||
// any.Unpack(foo)
|
||||
// ...
|
||||
//
|
||||
// Example 4: Pack and unpack a message in Go
|
||||
//
|
||||
// foo := &pb.Foo{...}
|
||||
// any, err := anypb.New(foo)
|
||||
// if err != nil {
|
||||
// ...
|
||||
// }
|
||||
// ...
|
||||
// foo := &pb.Foo{}
|
||||
// if err := any.UnmarshalTo(foo); err != nil {
|
||||
// ...
|
||||
// }
|
||||
//
|
||||
// The pack methods provided by protobuf library will by default use
|
||||
// 'type.googleapis.com/full.type.name' as the type URL and the unpack
|
||||
// methods only use the fully qualified type name after the last '/'
|
||||
// in the type URL, for example "foo.bar.com/x/y.z" will yield type
|
||||
// name "y.z".
|
||||
//
|
||||
// JSON
|
||||
//
|
||||
// The JSON representation of an `Any` value uses the regular
|
||||
// representation of the deserialized, embedded message, with an
|
||||
// additional field `@type` which contains the type URL. Example:
|
||||
//
|
||||
// package google.profile;
|
||||
// message Person {
|
||||
// string first_name = 1;
|
||||
// string last_name = 2;
|
||||
// }
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.profile.Person",
|
||||
// "firstName": <string>,
|
||||
// "lastName": <string>
|
||||
// }
|
||||
//
|
||||
// If the embedded message type is well-known and has a custom JSON
|
||||
// representation, that representation will be embedded adding a field
|
||||
// `value` which holds the custom JSON in addition to the `@type`
|
||||
// field. Example (for message [google.protobuf.Duration][]):
|
||||
//
|
||||
// {
|
||||
// "@type": "type.googleapis.com/google.protobuf.Duration",
|
||||
// "value": "1.212s"
|
||||
// }
|
||||
//
|
||||
message Any {
|
||||
// A URL/resource name that uniquely identifies the type of the serialized
|
||||
// protocol buffer message. This string must contain at least
|
||||
// one "/" character. The last segment of the URL's path must represent
|
||||
// the fully qualified name of the type (as in
|
||||
// `path/google.protobuf.Duration`). The name should be in a canonical form
|
||||
// (e.g., leading "." is not accepted).
|
||||
//
|
||||
// In practice, teams usually precompile into the binary all types that they
|
||||
// expect it to use in the context of Any. However, for URLs which use the
|
||||
// scheme `http`, `https`, or no scheme, one can optionally set up a type
|
||||
// server that maps type URLs to message definitions as follows:
|
||||
//
|
||||
// * If no scheme is provided, `https` is assumed.
|
||||
// * An HTTP GET on the URL must yield a [google.protobuf.Type][]
|
||||
// value in binary format, or produce an error.
|
||||
// * Applications are allowed to cache lookup results based on the
|
||||
// URL, or have them precompiled into a binary to avoid any
|
||||
// lookup. Therefore, binary compatibility needs to be preserved
|
||||
// on changes to types. (Use versioned type names to manage
|
||||
// breaking changes.)
|
||||
//
|
||||
// Note: this functionality is not currently available in the official
|
||||
// protobuf release, and it is not used for type URLs beginning with
|
||||
// type.googleapis.com.
|
||||
//
|
||||
// Schemes other than `http`, `https` (or the empty scheme) might be
|
||||
// used with implementation specific semantics.
|
||||
//
|
||||
string type_url = 1;
|
||||
|
||||
// Must be a valid serialized protocol buffer of the above specified type.
|
||||
bytes value = 2;
|
||||
}
|
||||
|
|
@ -1,921 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// The messages in this file describe the definitions found in .proto files.
|
||||
// A valid .proto file can be translated directly to a FileDescriptorProto
|
||||
// without any other information (e.g. without reading its imports).
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option go_package = "google.golang.org/protobuf/types/descriptorpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DescriptorProtos";
|
||||
option csharp_namespace = "Google.Protobuf.Reflection";
|
||||
option objc_class_prefix = "GPB";
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// descriptor.proto must be optimized for speed because reflection-based
|
||||
// algorithms don't work during bootstrapping.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
// The protocol compiler can output a FileDescriptorSet containing the .proto
|
||||
// files it parses.
|
||||
message FileDescriptorSet {
|
||||
repeated FileDescriptorProto file = 1;
|
||||
}
|
||||
|
||||
// Describes a complete .proto file.
|
||||
message FileDescriptorProto {
|
||||
optional string name = 1; // file name, relative to root of source tree
|
||||
optional string package = 2; // e.g. "foo", "foo.bar", etc.
|
||||
|
||||
// Names of files imported by this file.
|
||||
repeated string dependency = 3;
|
||||
// Indexes of the public imported files in the dependency list above.
|
||||
repeated int32 public_dependency = 10;
|
||||
// Indexes of the weak imported files in the dependency list.
|
||||
// For Google-internal migration only. Do not use.
|
||||
repeated int32 weak_dependency = 11;
|
||||
|
||||
// All top-level definitions in this file.
|
||||
repeated DescriptorProto message_type = 4;
|
||||
repeated EnumDescriptorProto enum_type = 5;
|
||||
repeated ServiceDescriptorProto service = 6;
|
||||
repeated FieldDescriptorProto extension = 7;
|
||||
|
||||
optional FileOptions options = 8;
|
||||
|
||||
// This field contains optional information about the original source code.
|
||||
// You may safely remove this entire field without harming runtime
|
||||
// functionality of the descriptors -- the information is needed only by
|
||||
// development tools.
|
||||
optional SourceCodeInfo source_code_info = 9;
|
||||
|
||||
// The syntax of the proto file.
|
||||
// The supported values are "proto2", "proto3", and "editions".
|
||||
//
|
||||
// If `edition` is present, this value must be "editions".
|
||||
optional string syntax = 12;
|
||||
|
||||
// The edition of the proto file, which is an opaque string.
|
||||
optional string edition = 13;
|
||||
}
|
||||
|
||||
// Describes a message type.
|
||||
message DescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated FieldDescriptorProto field = 2;
|
||||
repeated FieldDescriptorProto extension = 6;
|
||||
|
||||
repeated DescriptorProto nested_type = 3;
|
||||
repeated EnumDescriptorProto enum_type = 4;
|
||||
|
||||
message ExtensionRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Exclusive.
|
||||
|
||||
optional ExtensionRangeOptions options = 3;
|
||||
}
|
||||
repeated ExtensionRange extension_range = 5;
|
||||
|
||||
repeated OneofDescriptorProto oneof_decl = 8;
|
||||
|
||||
optional MessageOptions options = 7;
|
||||
|
||||
// Range of reserved tag numbers. Reserved tag numbers may not be used by
|
||||
// fields or extension ranges in the same message. Reserved ranges may
|
||||
// not overlap.
|
||||
message ReservedRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Exclusive.
|
||||
}
|
||||
repeated ReservedRange reserved_range = 9;
|
||||
// Reserved field names, which may not be used by fields in the same message.
|
||||
// A given name may only be reserved once.
|
||||
repeated string reserved_name = 10;
|
||||
}
|
||||
|
||||
message ExtensionRangeOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
// Describes a field within a message.
|
||||
message FieldDescriptorProto {
|
||||
enum Type {
|
||||
// 0 is reserved for errors.
|
||||
// Order is weird for historical reasons.
|
||||
TYPE_DOUBLE = 1;
|
||||
TYPE_FLOAT = 2;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT64 if
|
||||
// negative values are likely.
|
||||
TYPE_INT64 = 3;
|
||||
TYPE_UINT64 = 4;
|
||||
// Not ZigZag encoded. Negative numbers take 10 bytes. Use TYPE_SINT32 if
|
||||
// negative values are likely.
|
||||
TYPE_INT32 = 5;
|
||||
TYPE_FIXED64 = 6;
|
||||
TYPE_FIXED32 = 7;
|
||||
TYPE_BOOL = 8;
|
||||
TYPE_STRING = 9;
|
||||
// Tag-delimited aggregate.
|
||||
// Group type is deprecated and not supported in proto3. However, Proto3
|
||||
// implementations should still be able to parse the group wire format and
|
||||
// treat group fields as unknown fields.
|
||||
TYPE_GROUP = 10;
|
||||
TYPE_MESSAGE = 11; // Length-delimited aggregate.
|
||||
|
||||
// New in version 2.
|
||||
TYPE_BYTES = 12;
|
||||
TYPE_UINT32 = 13;
|
||||
TYPE_ENUM = 14;
|
||||
TYPE_SFIXED32 = 15;
|
||||
TYPE_SFIXED64 = 16;
|
||||
TYPE_SINT32 = 17; // Uses ZigZag encoding.
|
||||
TYPE_SINT64 = 18; // Uses ZigZag encoding.
|
||||
}
|
||||
|
||||
enum Label {
|
||||
// 0 is reserved for errors
|
||||
LABEL_OPTIONAL = 1;
|
||||
LABEL_REQUIRED = 2;
|
||||
LABEL_REPEATED = 3;
|
||||
}
|
||||
|
||||
optional string name = 1;
|
||||
optional int32 number = 3;
|
||||
optional Label label = 4;
|
||||
|
||||
// If type_name is set, this need not be set. If both this and type_name
|
||||
// are set, this must be one of TYPE_ENUM, TYPE_MESSAGE or TYPE_GROUP.
|
||||
optional Type type = 5;
|
||||
|
||||
// For message and enum types, this is the name of the type. If the name
|
||||
// starts with a '.', it is fully-qualified. Otherwise, C++-like scoping
|
||||
// rules are used to find the type (i.e. first the nested types within this
|
||||
// message are searched, then within the parent, on up to the root
|
||||
// namespace).
|
||||
optional string type_name = 6;
|
||||
|
||||
// For extensions, this is the name of the type being extended. It is
|
||||
// resolved in the same manner as type_name.
|
||||
optional string extendee = 2;
|
||||
|
||||
// For numeric types, contains the original text representation of the value.
|
||||
// For booleans, "true" or "false".
|
||||
// For strings, contains the default text contents (not escaped in any way).
|
||||
// For bytes, contains the C escaped value. All bytes >= 128 are escaped.
|
||||
optional string default_value = 7;
|
||||
|
||||
// If set, gives the index of a oneof in the containing type's oneof_decl
|
||||
// list. This field is a member of that oneof.
|
||||
optional int32 oneof_index = 9;
|
||||
|
||||
// JSON name of this field. The value is set by protocol compiler. If the
|
||||
// user has set a "json_name" option on this field, that option's value
|
||||
// will be used. Otherwise, it's deduced from the field's name by converting
|
||||
// it to camelCase.
|
||||
optional string json_name = 10;
|
||||
|
||||
optional FieldOptions options = 8;
|
||||
|
||||
// If true, this is a proto3 "optional". When a proto3 field is optional, it
|
||||
// tracks presence regardless of field type.
|
||||
//
|
||||
// When proto3_optional is true, this field must be belong to a oneof to
|
||||
// signal to old proto3 clients that presence is tracked for this field. This
|
||||
// oneof is known as a "synthetic" oneof, and this field must be its sole
|
||||
// member (each proto3 optional field gets its own synthetic oneof). Synthetic
|
||||
// oneofs exist in the descriptor only, and do not generate any API. Synthetic
|
||||
// oneofs must be ordered after all "real" oneofs.
|
||||
//
|
||||
// For message fields, proto3_optional doesn't create any semantic change,
|
||||
// since non-repeated message fields always track presence. However it still
|
||||
// indicates the semantic detail of whether the user wrote "optional" or not.
|
||||
// This can be useful for round-tripping the .proto file. For consistency we
|
||||
// give message fields a synthetic oneof also, even though it is not required
|
||||
// to track presence. This is especially important because the parser can't
|
||||
// tell if a field is a message or an enum, so it must always create a
|
||||
// synthetic oneof.
|
||||
//
|
||||
// Proto2 optional fields do not set this flag, because they already indicate
|
||||
// optional with `LABEL_OPTIONAL`.
|
||||
optional bool proto3_optional = 17;
|
||||
}
|
||||
|
||||
// Describes a oneof.
|
||||
message OneofDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional OneofOptions options = 2;
|
||||
}
|
||||
|
||||
// Describes an enum type.
|
||||
message EnumDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
repeated EnumValueDescriptorProto value = 2;
|
||||
|
||||
optional EnumOptions options = 3;
|
||||
|
||||
// Range of reserved numeric values. Reserved values may not be used by
|
||||
// entries in the same enum. Reserved ranges may not overlap.
|
||||
//
|
||||
// Note that this is distinct from DescriptorProto.ReservedRange in that it
|
||||
// is inclusive such that it can appropriately represent the entire int32
|
||||
// domain.
|
||||
message EnumReservedRange {
|
||||
optional int32 start = 1; // Inclusive.
|
||||
optional int32 end = 2; // Inclusive.
|
||||
}
|
||||
|
||||
// Range of reserved numeric values. Reserved numeric values may not be used
|
||||
// by enum values in the same enum declaration. Reserved ranges may not
|
||||
// overlap.
|
||||
repeated EnumReservedRange reserved_range = 4;
|
||||
|
||||
// Reserved enum value names, which may not be reused. A given name may only
|
||||
// be reserved once.
|
||||
repeated string reserved_name = 5;
|
||||
}
|
||||
|
||||
// Describes a value within an enum.
|
||||
message EnumValueDescriptorProto {
|
||||
optional string name = 1;
|
||||
optional int32 number = 2;
|
||||
|
||||
optional EnumValueOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a service.
|
||||
message ServiceDescriptorProto {
|
||||
optional string name = 1;
|
||||
repeated MethodDescriptorProto method = 2;
|
||||
|
||||
optional ServiceOptions options = 3;
|
||||
}
|
||||
|
||||
// Describes a method of a service.
|
||||
message MethodDescriptorProto {
|
||||
optional string name = 1;
|
||||
|
||||
// Input and output type names. These are resolved in the same way as
|
||||
// FieldDescriptorProto.type_name, but must refer to a message type.
|
||||
optional string input_type = 2;
|
||||
optional string output_type = 3;
|
||||
|
||||
optional MethodOptions options = 4;
|
||||
|
||||
// Identifies if client streams multiple client messages
|
||||
optional bool client_streaming = 5 [default = false];
|
||||
// Identifies if server streams multiple server messages
|
||||
optional bool server_streaming = 6 [default = false];
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Options
|
||||
|
||||
// Each of the definitions above may have "options" attached. These are
|
||||
// just annotations which may cause code to be generated slightly differently
|
||||
// or may contain hints for code that manipulates protocol messages.
|
||||
//
|
||||
// Clients may define custom options as extensions of the *Options messages.
|
||||
// These extensions may not yet be known at parsing time, so the parser cannot
|
||||
// store the values in them. Instead it stores them in a field in the *Options
|
||||
// message called uninterpreted_option. This field must have the same name
|
||||
// across all *Options messages. We then use this field to populate the
|
||||
// extensions when we build a descriptor, at which point all protos have been
|
||||
// parsed and so all extensions are known.
|
||||
//
|
||||
// Extension numbers for custom options may be chosen as follows:
|
||||
// * For options which will only be used within a single application or
|
||||
// organization, or for experimental options, use field numbers 50000
|
||||
// through 99999. It is up to you to ensure that you do not use the
|
||||
// same number for multiple options.
|
||||
// * For options which will be published and used publicly by multiple
|
||||
// independent entities, e-mail protobuf-global-extension-registry@google.com
|
||||
// to reserve extension numbers. Simply provide your project name (e.g.
|
||||
// Objective-C plugin) and your project website (if available) -- there's no
|
||||
// need to explain how you intend to use them. Usually you only need one
|
||||
// extension number. You can declare multiple options with only one extension
|
||||
// number by putting them in a sub-message. See the Custom Options section of
|
||||
// the docs for examples:
|
||||
// https://developers.google.com/protocol-buffers/docs/proto#options
|
||||
// If this turns out to be popular, a web service will be set up
|
||||
// to automatically assign option numbers.
|
||||
|
||||
message FileOptions {
|
||||
|
||||
// Sets the Java package where classes generated from this .proto will be
|
||||
// placed. By default, the proto package is used, but this is often
|
||||
// inappropriate because proto packages do not normally start with backwards
|
||||
// domain names.
|
||||
optional string java_package = 1;
|
||||
|
||||
// Controls the name of the wrapper Java class generated for the .proto file.
|
||||
// That class will always contain the .proto file's getDescriptor() method as
|
||||
// well as any top-level extensions defined in the .proto file.
|
||||
// If java_multiple_files is disabled, then all the other classes from the
|
||||
// .proto file will be nested inside the single wrapper outer class.
|
||||
optional string java_outer_classname = 8;
|
||||
|
||||
// If enabled, then the Java code generator will generate a separate .java
|
||||
// file for each top-level message, enum, and service defined in the .proto
|
||||
// file. Thus, these types will *not* be nested inside the wrapper class
|
||||
// named by java_outer_classname. However, the wrapper class will still be
|
||||
// generated to contain the file's getDescriptor() method as well as any
|
||||
// top-level extensions defined in the file.
|
||||
optional bool java_multiple_files = 10 [default = false];
|
||||
|
||||
// This option does nothing.
|
||||
optional bool java_generate_equals_and_hash = 20 [deprecated = true];
|
||||
|
||||
// If set true, then the Java2 code generator will generate code that
|
||||
// throws an exception whenever an attempt is made to assign a non-UTF-8
|
||||
// byte sequence to a string field.
|
||||
// Message reflection will do the same.
|
||||
// However, an extension field still accepts non-UTF-8 byte sequences.
|
||||
// This option has no effect on when used with the lite runtime.
|
||||
optional bool java_string_check_utf8 = 27 [default = false];
|
||||
|
||||
// Generated classes can be optimized for speed or code size.
|
||||
enum OptimizeMode {
|
||||
SPEED = 1; // Generate complete code for parsing, serialization,
|
||||
// etc.
|
||||
CODE_SIZE = 2; // Use ReflectionOps to implement these methods.
|
||||
LITE_RUNTIME = 3; // Generate code using MessageLite and the lite runtime.
|
||||
}
|
||||
optional OptimizeMode optimize_for = 9 [default = SPEED];
|
||||
|
||||
// Sets the Go package where structs generated from this .proto will be
|
||||
// placed. If omitted, the Go package will be derived from the following:
|
||||
// - The basename of the package import path, if provided.
|
||||
// - Otherwise, the package statement in the .proto file, if present.
|
||||
// - Otherwise, the basename of the .proto file, without extension.
|
||||
optional string go_package = 11;
|
||||
|
||||
// Should generic services be generated in each language? "Generic" services
|
||||
// are not specific to any particular RPC system. They are generated by the
|
||||
// main code generators in each language (without additional plugins).
|
||||
// Generic services were the only kind of service generation supported by
|
||||
// early versions of google.protobuf.
|
||||
//
|
||||
// Generic services are now considered deprecated in favor of using plugins
|
||||
// that generate code specific to your particular RPC system. Therefore,
|
||||
// these default to false. Old code which depends on generic services should
|
||||
// explicitly set them to true.
|
||||
optional bool cc_generic_services = 16 [default = false];
|
||||
optional bool java_generic_services = 17 [default = false];
|
||||
optional bool py_generic_services = 18 [default = false];
|
||||
optional bool php_generic_services = 42 [default = false];
|
||||
|
||||
// Is this file deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for everything in the file, or it will be completely ignored; in the very
|
||||
// least, this is a formalization for deprecating files.
|
||||
optional bool deprecated = 23 [default = false];
|
||||
|
||||
// Enables the use of arenas for the proto messages in this file. This applies
|
||||
// only to generated classes for C++.
|
||||
optional bool cc_enable_arenas = 31 [default = true];
|
||||
|
||||
// Sets the objective c class prefix which is prepended to all objective c
|
||||
// generated classes from this .proto. There is no default.
|
||||
optional string objc_class_prefix = 36;
|
||||
|
||||
// Namespace for generated classes; defaults to the package.
|
||||
optional string csharp_namespace = 37;
|
||||
|
||||
// By default Swift generators will take the proto package and CamelCase it
|
||||
// replacing '.' with underscore and use that to prefix the types/symbols
|
||||
// defined. When this options is provided, they will use this value instead
|
||||
// to prefix the types/symbols defined.
|
||||
optional string swift_prefix = 39;
|
||||
|
||||
// Sets the php class prefix which is prepended to all php generated classes
|
||||
// from this .proto. Default is empty.
|
||||
optional string php_class_prefix = 40;
|
||||
|
||||
// Use this option to change the namespace of php generated classes. Default
|
||||
// is empty. When this option is empty, the package name will be used for
|
||||
// determining the namespace.
|
||||
optional string php_namespace = 41;
|
||||
|
||||
// Use this option to change the namespace of php generated metadata classes.
|
||||
// Default is empty. When this option is empty, the proto file name will be
|
||||
// used for determining the namespace.
|
||||
optional string php_metadata_namespace = 44;
|
||||
|
||||
// Use this option to change the package of ruby generated classes. Default
|
||||
// is empty. When this option is not set, the package name will be used for
|
||||
// determining the ruby package.
|
||||
optional string ruby_package = 45;
|
||||
|
||||
// The parser stores options it doesn't recognize here.
|
||||
// See the documentation for the "Options" section above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message.
|
||||
// See the documentation for the "Options" section above.
|
||||
extensions 1000 to max;
|
||||
|
||||
reserved 38;
|
||||
}
|
||||
|
||||
message MessageOptions {
|
||||
// Set true to use the old proto1 MessageSet wire format for extensions.
|
||||
// This is provided for backwards-compatibility with the MessageSet wire
|
||||
// format. You should not use this for any other reason: It's less
|
||||
// efficient, has fewer features, and is more complicated.
|
||||
//
|
||||
// The message must be defined exactly as follows:
|
||||
// message Foo {
|
||||
// option message_set_wire_format = true;
|
||||
// extensions 4 to max;
|
||||
// }
|
||||
// Note that the message cannot have any defined fields; MessageSets only
|
||||
// have extensions.
|
||||
//
|
||||
// All extensions of your type must be singular messages; e.g. they cannot
|
||||
// be int32s, enums, or repeated messages.
|
||||
//
|
||||
// Because this is an option, the above two restrictions are not enforced by
|
||||
// the protocol compiler.
|
||||
optional bool message_set_wire_format = 1 [default = false];
|
||||
|
||||
// Disables the generation of the standard "descriptor()" accessor, which can
|
||||
// conflict with a field of the same name. This is meant to make migration
|
||||
// from proto1 easier; new code should avoid fields named "descriptor".
|
||||
optional bool no_standard_descriptor_accessor = 2 [default = false];
|
||||
|
||||
// Is this message deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the message, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating messages.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
reserved 4, 5, 6;
|
||||
|
||||
// NOTE: Do not set the option in .proto files. Always use the maps syntax
|
||||
// instead. The option should only be implicitly set by the proto compiler
|
||||
// parser.
|
||||
//
|
||||
// Whether the message is an automatically generated map entry type for the
|
||||
// maps field.
|
||||
//
|
||||
// For maps fields:
|
||||
// map<KeyType, ValueType> map_field = 1;
|
||||
// The parsed descriptor looks like:
|
||||
// message MapFieldEntry {
|
||||
// option map_entry = true;
|
||||
// optional KeyType key = 1;
|
||||
// optional ValueType value = 2;
|
||||
// }
|
||||
// repeated MapFieldEntry map_field = 1;
|
||||
//
|
||||
// Implementations may choose not to generate the map_entry=true message, but
|
||||
// use a native map in the target language to hold the keys and values.
|
||||
// The reflection APIs in such implementations still need to work as
|
||||
// if the field is a repeated message field.
|
||||
optional bool map_entry = 7;
|
||||
|
||||
reserved 8; // javalite_serializable
|
||||
reserved 9; // javanano_as_lite
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message FieldOptions {
|
||||
// The ctype option instructs the C++ code generator to use a different
|
||||
// representation of the field than it normally would. See the specific
|
||||
// options below. This option is not yet implemented in the open source
|
||||
// release -- sorry, we'll try to include it in a future version!
|
||||
optional CType ctype = 1 [default = STRING];
|
||||
enum CType {
|
||||
// Default mode.
|
||||
STRING = 0;
|
||||
|
||||
CORD = 1;
|
||||
|
||||
STRING_PIECE = 2;
|
||||
}
|
||||
// The packed option can be enabled for repeated primitive fields to enable
|
||||
// a more efficient representation on the wire. Rather than repeatedly
|
||||
// writing the tag and type for each element, the entire array is encoded as
|
||||
// a single length-delimited blob. In proto3, only explicit setting it to
|
||||
// false will avoid using packed encoding.
|
||||
optional bool packed = 2;
|
||||
|
||||
// The jstype option determines the JavaScript type used for values of the
|
||||
// field. The option is permitted only for 64 bit integral and fixed types
|
||||
// (int64, uint64, sint64, fixed64, sfixed64). A field with jstype JS_STRING
|
||||
// is represented as JavaScript string, which avoids loss of precision that
|
||||
// can happen when a large value is converted to a floating point JavaScript.
|
||||
// Specifying JS_NUMBER for the jstype causes the generated JavaScript code to
|
||||
// use the JavaScript "number" type. The behavior of the default option
|
||||
// JS_NORMAL is implementation dependent.
|
||||
//
|
||||
// This option is an enum to permit additional types to be added, e.g.
|
||||
// goog.math.Integer.
|
||||
optional JSType jstype = 6 [default = JS_NORMAL];
|
||||
enum JSType {
|
||||
// Use the default type.
|
||||
JS_NORMAL = 0;
|
||||
|
||||
// Use JavaScript strings.
|
||||
JS_STRING = 1;
|
||||
|
||||
// Use JavaScript numbers.
|
||||
JS_NUMBER = 2;
|
||||
}
|
||||
|
||||
// Should this field be parsed lazily? Lazy applies only to message-type
|
||||
// fields. It means that when the outer message is initially parsed, the
|
||||
// inner message's contents will not be parsed but instead stored in encoded
|
||||
// form. The inner message will actually be parsed when it is first accessed.
|
||||
//
|
||||
// This is only a hint. Implementations are free to choose whether to use
|
||||
// eager or lazy parsing regardless of the value of this option. However,
|
||||
// setting this option true suggests that the protocol author believes that
|
||||
// using lazy parsing on this field is worth the additional bookkeeping
|
||||
// overhead typically needed to implement it.
|
||||
//
|
||||
// This option does not affect the public interface of any generated code;
|
||||
// all method signatures remain the same. Furthermore, thread-safety of the
|
||||
// interface is not affected by this option; const methods remain safe to
|
||||
// call from multiple threads concurrently, while non-const methods continue
|
||||
// to require exclusive access.
|
||||
//
|
||||
// Note that implementations may choose not to check required fields within
|
||||
// a lazy sub-message. That is, calling IsInitialized() on the outer message
|
||||
// may return true even if the inner message has missing required fields.
|
||||
// This is necessary because otherwise the inner message would have to be
|
||||
// parsed in order to perform the check, defeating the purpose of lazy
|
||||
// parsing. An implementation which chooses not to check required fields
|
||||
// must be consistent about it. That is, for any particular sub-message, the
|
||||
// implementation must either *always* check its required fields, or *never*
|
||||
// check its required fields, regardless of whether or not the message has
|
||||
// been parsed.
|
||||
//
|
||||
// As of May 2022, lazy verifies the contents of the byte stream during
|
||||
// parsing. An invalid byte stream will cause the overall parsing to fail.
|
||||
optional bool lazy = 5 [default = false];
|
||||
|
||||
// unverified_lazy does no correctness checks on the byte stream. This should
|
||||
// only be used where lazy with verification is prohibitive for performance
|
||||
// reasons.
|
||||
optional bool unverified_lazy = 15 [default = false];
|
||||
|
||||
// Is this field deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for accessors, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating fields.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
// For Google-internal migration only. Do not use.
|
||||
optional bool weak = 10 [default = false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
|
||||
reserved 4; // removed jtype
|
||||
}
|
||||
|
||||
message OneofOptions {
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumOptions {
|
||||
|
||||
// Set this option to true to allow mapping different tag names to the same
|
||||
// value.
|
||||
optional bool allow_alias = 2;
|
||||
|
||||
// Is this enum deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum, or it will be completely ignored; in the very least, this
|
||||
// is a formalization for deprecating enums.
|
||||
optional bool deprecated = 3 [default = false];
|
||||
|
||||
reserved 5; // javanano_as_lite
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message EnumValueOptions {
|
||||
// Is this enum value deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the enum value, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating enum values.
|
||||
optional bool deprecated = 1 [default = false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message ServiceOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this service deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the service, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating services.
|
||||
optional bool deprecated = 33 [default = false];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
message MethodOptions {
|
||||
|
||||
// Note: Field numbers 1 through 32 are reserved for Google's internal RPC
|
||||
// framework. We apologize for hoarding these numbers to ourselves, but
|
||||
// we were already using them long before we decided to release Protocol
|
||||
// Buffers.
|
||||
|
||||
// Is this method deprecated?
|
||||
// Depending on the target platform, this can emit Deprecated annotations
|
||||
// for the method, or it will be completely ignored; in the very least,
|
||||
// this is a formalization for deprecating methods.
|
||||
optional bool deprecated = 33 [default = false];
|
||||
|
||||
// Is this method side-effect-free (or safe in HTTP parlance), or idempotent,
|
||||
// or neither? HTTP based RPC implementation may choose GET verb for safe
|
||||
// methods, and PUT verb for idempotent methods instead of the default POST.
|
||||
enum IdempotencyLevel {
|
||||
IDEMPOTENCY_UNKNOWN = 0;
|
||||
NO_SIDE_EFFECTS = 1; // implies idempotent
|
||||
IDEMPOTENT = 2; // idempotent, but may have side effects
|
||||
}
|
||||
optional IdempotencyLevel idempotency_level = 34
|
||||
[default = IDEMPOTENCY_UNKNOWN];
|
||||
|
||||
// The parser stores options it doesn't recognize here. See above.
|
||||
repeated UninterpretedOption uninterpreted_option = 999;
|
||||
|
||||
// Clients can define custom options in extensions of this message. See above.
|
||||
extensions 1000 to max;
|
||||
}
|
||||
|
||||
// A message representing a option the parser does not recognize. This only
|
||||
// appears in options protos created by the compiler::Parser class.
|
||||
// DescriptorPool resolves these when building Descriptor objects. Therefore,
|
||||
// options protos in descriptor objects (e.g. returned by Descriptor::options(),
|
||||
// or produced by Descriptor::CopyTo()) will never have UninterpretedOptions
|
||||
// in them.
|
||||
message UninterpretedOption {
|
||||
// The name of the uninterpreted option. Each string represents a segment in
|
||||
// a dot-separated name. is_extension is true iff a segment represents an
|
||||
// extension (denoted with parentheses in options specs in .proto files).
|
||||
// E.g.,{ ["foo", false], ["bar.baz", true], ["moo", false] } represents
|
||||
// "foo.(bar.baz).moo".
|
||||
message NamePart {
|
||||
required string name_part = 1;
|
||||
required bool is_extension = 2;
|
||||
}
|
||||
repeated NamePart name = 2;
|
||||
|
||||
// The value of the uninterpreted option, in whatever type the tokenizer
|
||||
// identified it as during parsing. Exactly one of these should be set.
|
||||
optional string identifier_value = 3;
|
||||
optional uint64 positive_int_value = 4;
|
||||
optional int64 negative_int_value = 5;
|
||||
optional double double_value = 6;
|
||||
optional bytes string_value = 7;
|
||||
optional string aggregate_value = 8;
|
||||
}
|
||||
|
||||
// ===================================================================
|
||||
// Optional source code info
|
||||
|
||||
// Encapsulates information about the original source file from which a
|
||||
// FileDescriptorProto was generated.
|
||||
message SourceCodeInfo {
|
||||
// A Location identifies a piece of source code in a .proto file which
|
||||
// corresponds to a particular definition. This information is intended
|
||||
// to be useful to IDEs, code indexers, documentation generators, and similar
|
||||
// tools.
|
||||
//
|
||||
// For example, say we have a file like:
|
||||
// message Foo {
|
||||
// optional string foo = 1;
|
||||
// }
|
||||
// Let's look at just the field definition:
|
||||
// optional string foo = 1;
|
||||
// ^ ^^ ^^ ^ ^^^
|
||||
// a bc de f ghi
|
||||
// We have the following locations:
|
||||
// span path represents
|
||||
// [a,i) [ 4, 0, 2, 0 ] The whole field definition.
|
||||
// [a,b) [ 4, 0, 2, 0, 4 ] The label (optional).
|
||||
// [c,d) [ 4, 0, 2, 0, 5 ] The type (string).
|
||||
// [e,f) [ 4, 0, 2, 0, 1 ] The name (foo).
|
||||
// [g,h) [ 4, 0, 2, 0, 3 ] The number (1).
|
||||
//
|
||||
// Notes:
|
||||
// - A location may refer to a repeated field itself (i.e. not to any
|
||||
// particular index within it). This is used whenever a set of elements are
|
||||
// logically enclosed in a single code segment. For example, an entire
|
||||
// extend block (possibly containing multiple extension definitions) will
|
||||
// have an outer location whose path refers to the "extensions" repeated
|
||||
// field without an index.
|
||||
// - Multiple locations may have the same path. This happens when a single
|
||||
// logical declaration is spread out across multiple places. The most
|
||||
// obvious example is the "extend" block again -- there may be multiple
|
||||
// extend blocks in the same scope, each of which will have the same path.
|
||||
// - A location's span is not always a subset of its parent's span. For
|
||||
// example, the "extendee" of an extension declaration appears at the
|
||||
// beginning of the "extend" block and is shared by all extensions within
|
||||
// the block.
|
||||
// - Just because a location's span is a subset of some other location's span
|
||||
// does not mean that it is a descendant. For example, a "group" defines
|
||||
// both a type and a field in a single declaration. Thus, the locations
|
||||
// corresponding to the type and field and their components will overlap.
|
||||
// - Code which tries to interpret locations should probably be designed to
|
||||
// ignore those that it doesn't understand, as more types of locations could
|
||||
// be recorded in the future.
|
||||
repeated Location location = 1;
|
||||
message Location {
|
||||
// Identifies which part of the FileDescriptorProto was defined at this
|
||||
// location.
|
||||
//
|
||||
// Each element is a field number or an index. They form a path from
|
||||
// the root FileDescriptorProto to the place where the definition occurs.
|
||||
// For example, this path:
|
||||
// [ 4, 3, 2, 7, 1 ]
|
||||
// refers to:
|
||||
// file.message_type(3) // 4, 3
|
||||
// .field(7) // 2, 7
|
||||
// .name() // 1
|
||||
// This is because FileDescriptorProto.message_type has field number 4:
|
||||
// repeated DescriptorProto message_type = 4;
|
||||
// and DescriptorProto.field has field number 2:
|
||||
// repeated FieldDescriptorProto field = 2;
|
||||
// and FieldDescriptorProto.name has field number 1:
|
||||
// optional string name = 1;
|
||||
//
|
||||
// Thus, the above path gives the location of a field name. If we removed
|
||||
// the last element:
|
||||
// [ 4, 3, 2, 7 ]
|
||||
// this path refers to the whole field declaration (from the beginning
|
||||
// of the label to the terminating semicolon).
|
||||
repeated int32 path = 1 [packed = true];
|
||||
|
||||
// Always has exactly three or four elements: start line, start column,
|
||||
// end line (optional, otherwise assumed same as start line), end column.
|
||||
// These are packed into a single field for efficiency. Note that line
|
||||
// and column numbers are zero-based -- typically you will want to add
|
||||
// 1 to each before displaying to a user.
|
||||
repeated int32 span = 2 [packed = true];
|
||||
|
||||
// If this SourceCodeInfo represents a complete declaration, these are any
|
||||
// comments appearing before and after the declaration which appear to be
|
||||
// attached to the declaration.
|
||||
//
|
||||
// A series of line comments appearing on consecutive lines, with no other
|
||||
// tokens appearing on those lines, will be treated as a single comment.
|
||||
//
|
||||
// leading_detached_comments will keep paragraphs of comments that appear
|
||||
// before (but not connected to) the current element. Each paragraph,
|
||||
// separated by empty lines, will be one comment element in the repeated
|
||||
// field.
|
||||
//
|
||||
// Only the comment content is provided; comment markers (e.g. //) are
|
||||
// stripped out. For block comments, leading whitespace and an asterisk
|
||||
// will be stripped from the beginning of each line other than the first.
|
||||
// Newlines are included in the output.
|
||||
//
|
||||
// Examples:
|
||||
//
|
||||
// optional int32 foo = 1; // Comment attached to foo.
|
||||
// // Comment attached to bar.
|
||||
// optional int32 bar = 2;
|
||||
//
|
||||
// optional string baz = 3;
|
||||
// // Comment attached to baz.
|
||||
// // Another line attached to baz.
|
||||
//
|
||||
// // Comment attached to moo.
|
||||
// //
|
||||
// // Another line attached to moo.
|
||||
// optional double moo = 4;
|
||||
//
|
||||
// // Detached comment for corge. This is not leading or trailing comments
|
||||
// // to moo or corge because there are blank lines separating it from
|
||||
// // both.
|
||||
//
|
||||
// // Detached comment for corge paragraph 2.
|
||||
//
|
||||
// optional string corge = 5;
|
||||
// /* Block comment attached
|
||||
// * to corge. Leading asterisks
|
||||
// * will be removed. */
|
||||
// /* Block comment attached to
|
||||
// * grault. */
|
||||
// optional int32 grault = 6;
|
||||
//
|
||||
// // ignored detached comments.
|
||||
optional string leading_comments = 3;
|
||||
optional string trailing_comments = 4;
|
||||
repeated string leading_detached_comments = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// Describes the relationship between generated code and its original source
|
||||
// file. A GeneratedCodeInfo message is associated with only one generated
|
||||
// source file, but may contain references to different source .proto files.
|
||||
message GeneratedCodeInfo {
|
||||
// An Annotation connects some span of text in generated code to an element
|
||||
// of its generating .proto file.
|
||||
repeated Annotation annotation = 1;
|
||||
message Annotation {
|
||||
// Identifies the element in the original source .proto file. This field
|
||||
// is formatted the same as SourceCodeInfo.Location.path.
|
||||
repeated int32 path = 1 [packed = true];
|
||||
|
||||
// Identifies the filesystem path to the original source .proto.
|
||||
optional string source_file = 2;
|
||||
|
||||
// Identifies the starting offset in bytes in the generated code
|
||||
// that relates to the identified object.
|
||||
optional int32 begin = 3;
|
||||
|
||||
// Identifies the ending offset in bytes in the generated code that
|
||||
// relates to the identified object. The end offset should be one past
|
||||
// the last relevant byte (so the length of the text = end - begin).
|
||||
optional int32 end = 4;
|
||||
|
||||
// Represents the identified object's effect on the element in the original
|
||||
// .proto file.
|
||||
enum Semantic {
|
||||
// There is no effect or the effect is indescribable.
|
||||
NONE = 0;
|
||||
// The element is set or otherwise mutated.
|
||||
SET = 1;
|
||||
// An alias to the element is returned.
|
||||
ALIAS = 2;
|
||||
}
|
||||
optional Semantic semantic = 5;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/durationpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "DurationProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
|
||||
// A Duration represents a signed, fixed-length span of time represented
|
||||
// as a count of seconds and fractions of seconds at nanosecond
|
||||
// resolution. It is independent of any calendar and concepts like "day"
|
||||
// or "month". It is related to Timestamp in that the difference between
|
||||
// two Timestamp values is a Duration and it can be added or subtracted
|
||||
// from a Timestamp. Range is approximately +-10,000 years.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Duration from two Timestamps in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Timestamp end = ...;
|
||||
// Duration duration = ...;
|
||||
//
|
||||
// duration.seconds = end.seconds - start.seconds;
|
||||
// duration.nanos = end.nanos - start.nanos;
|
||||
//
|
||||
// if (duration.seconds < 0 && duration.nanos > 0) {
|
||||
// duration.seconds += 1;
|
||||
// duration.nanos -= 1000000000;
|
||||
// } else if (duration.seconds > 0 && duration.nanos < 0) {
|
||||
// duration.seconds -= 1;
|
||||
// duration.nanos += 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 2: Compute Timestamp from Timestamp + Duration in pseudo code.
|
||||
//
|
||||
// Timestamp start = ...;
|
||||
// Duration duration = ...;
|
||||
// Timestamp end = ...;
|
||||
//
|
||||
// end.seconds = start.seconds + duration.seconds;
|
||||
// end.nanos = start.nanos + duration.nanos;
|
||||
//
|
||||
// if (end.nanos < 0) {
|
||||
// end.seconds -= 1;
|
||||
// end.nanos += 1000000000;
|
||||
// } else if (end.nanos >= 1000000000) {
|
||||
// end.seconds += 1;
|
||||
// end.nanos -= 1000000000;
|
||||
// }
|
||||
//
|
||||
// Example 3: Compute Duration from datetime.timedelta in Python.
|
||||
//
|
||||
// td = datetime.timedelta(days=3, minutes=10)
|
||||
// duration = Duration()
|
||||
// duration.FromTimedelta(td)
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Duration type is encoded as a string rather than an
|
||||
// object, where the string ends in the suffix "s" (indicating seconds) and
|
||||
// is preceded by the number of seconds, with nanoseconds expressed as
|
||||
// fractional seconds. For example, 3 seconds with 0 nanoseconds should be
|
||||
// encoded in JSON format as "3s", while 3 seconds and 1 nanosecond should
|
||||
// be expressed in JSON format as "3.000000001s", and 3 seconds and 1
|
||||
// microsecond should be expressed in JSON format as "3.000001s".
|
||||
//
|
||||
message Duration {
|
||||
// Signed seconds of the span of time. Must be from -315,576,000,000
|
||||
// to +315,576,000,000 inclusive. Note: these bounds are computed from:
|
||||
// 60 sec/min * 60 min/hr * 24 hr/day * 365.25 days/year * 10000 years
|
||||
int64 seconds = 1;
|
||||
|
||||
// Signed fractions of a second at nanosecond resolution of the span
|
||||
// of time. Durations less than one second are represented with a 0
|
||||
// `seconds` field and a positive or negative `nanos` field. For durations
|
||||
// of one second or more, a non-zero value for the `nanos` field must be
|
||||
// of the same sign as the `seconds` field. Must be from -999,999,999
|
||||
// to +999,999,999 inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "FieldMaskProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/fieldmaskpb";
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// `FieldMask` represents a set of symbolic field paths, for example:
|
||||
//
|
||||
// paths: "f.a"
|
||||
// paths: "f.b.d"
|
||||
//
|
||||
// Here `f` represents a field in some root message, `a` and `b`
|
||||
// fields in the message found in `f`, and `d` a field found in the
|
||||
// message in `f.b`.
|
||||
//
|
||||
// Field masks are used to specify a subset of fields that should be
|
||||
// returned by a get operation or modified by an update operation.
|
||||
// Field masks also have a custom JSON encoding (see below).
|
||||
//
|
||||
// # Field Masks in Projections
|
||||
//
|
||||
// When used in the context of a projection, a response message or
|
||||
// sub-message is filtered by the API to only contain those fields as
|
||||
// specified in the mask. For example, if the mask in the previous
|
||||
// example is applied to a response message as follows:
|
||||
//
|
||||
// f {
|
||||
// a : 22
|
||||
// b {
|
||||
// d : 1
|
||||
// x : 2
|
||||
// }
|
||||
// y : 13
|
||||
// }
|
||||
// z: 8
|
||||
//
|
||||
// The result will not contain specific values for fields x,y and z
|
||||
// (their value will be set to the default, and omitted in proto text
|
||||
// output):
|
||||
//
|
||||
//
|
||||
// f {
|
||||
// a : 22
|
||||
// b {
|
||||
// d : 1
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// A repeated field is not allowed except at the last position of a
|
||||
// paths string.
|
||||
//
|
||||
// If a FieldMask object is not present in a get operation, the
|
||||
// operation applies to all fields (as if a FieldMask of all fields
|
||||
// had been specified).
|
||||
//
|
||||
// Note that a field mask does not necessarily apply to the
|
||||
// top-level response message. In case of a REST get operation, the
|
||||
// field mask applies directly to the response, but in case of a REST
|
||||
// list operation, the mask instead applies to each individual message
|
||||
// in the returned resource list. In case of a REST custom method,
|
||||
// other definitions may be used. Where the mask applies will be
|
||||
// clearly documented together with its declaration in the API. In
|
||||
// any case, the effect on the returned resource/resources is required
|
||||
// behavior for APIs.
|
||||
//
|
||||
// # Field Masks in Update Operations
|
||||
//
|
||||
// A field mask in update operations specifies which fields of the
|
||||
// targeted resource are going to be updated. The API is required
|
||||
// to only change the values of the fields as specified in the mask
|
||||
// and leave the others untouched. If a resource is passed in to
|
||||
// describe the updated values, the API ignores the values of all
|
||||
// fields not covered by the mask.
|
||||
//
|
||||
// If a repeated field is specified for an update operation, new values will
|
||||
// be appended to the existing repeated field in the target resource. Note that
|
||||
// a repeated field is only allowed in the last position of a `paths` string.
|
||||
//
|
||||
// If a sub-message is specified in the last position of the field mask for an
|
||||
// update operation, then new value will be merged into the existing sub-message
|
||||
// in the target resource.
|
||||
//
|
||||
// For example, given the target message:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 1
|
||||
// x: 2
|
||||
// }
|
||||
// c: [1]
|
||||
// }
|
||||
//
|
||||
// And an update message:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 10
|
||||
// }
|
||||
// c: [2]
|
||||
// }
|
||||
//
|
||||
// then if the field mask is:
|
||||
//
|
||||
// paths: ["f.b", "f.c"]
|
||||
//
|
||||
// then the result will be:
|
||||
//
|
||||
// f {
|
||||
// b {
|
||||
// d: 10
|
||||
// x: 2
|
||||
// }
|
||||
// c: [1, 2]
|
||||
// }
|
||||
//
|
||||
// An implementation may provide options to override this default behavior for
|
||||
// repeated and message fields.
|
||||
//
|
||||
// In order to reset a field's value to the default, the field must
|
||||
// be in the mask and set to the default value in the provided resource.
|
||||
// Hence, in order to reset all fields of a resource, provide a default
|
||||
// instance of the resource and set all fields in the mask, or do
|
||||
// not provide a mask as described below.
|
||||
//
|
||||
// If a field mask is not present on update, the operation applies to
|
||||
// all fields (as if a field mask of all fields has been specified).
|
||||
// Note that in the presence of schema evolution, this may mean that
|
||||
// fields the client does not know and has therefore not filled into
|
||||
// the request will be reset to their default. If this is unwanted
|
||||
// behavior, a specific service may require a client to always specify
|
||||
// a field mask, producing an error if not.
|
||||
//
|
||||
// As with get operations, the location of the resource which
|
||||
// describes the updated values in the request message depends on the
|
||||
// operation kind. In any case, the effect of the field mask is
|
||||
// required to be honored by the API.
|
||||
//
|
||||
// ## Considerations for HTTP REST
|
||||
//
|
||||
// The HTTP kind of an update operation which uses a field mask must
|
||||
// be set to PATCH instead of PUT in order to satisfy HTTP semantics
|
||||
// (PUT must only be used for full updates).
|
||||
//
|
||||
// # JSON Encoding of Field Masks
|
||||
//
|
||||
// In JSON, a field mask is encoded as a single string where paths are
|
||||
// separated by a comma. Fields name in each path are converted
|
||||
// to/from lower-camel naming conventions.
|
||||
//
|
||||
// As an example, consider the following message declarations:
|
||||
//
|
||||
// message Profile {
|
||||
// User user = 1;
|
||||
// Photo photo = 2;
|
||||
// }
|
||||
// message User {
|
||||
// string display_name = 1;
|
||||
// string address = 2;
|
||||
// }
|
||||
//
|
||||
// In proto a field mask for `Profile` may look as such:
|
||||
//
|
||||
// mask {
|
||||
// paths: "user.display_name"
|
||||
// paths: "photo"
|
||||
// }
|
||||
//
|
||||
// In JSON, the same mask is represented as below:
|
||||
//
|
||||
// {
|
||||
// mask: "user.displayName,photo"
|
||||
// }
|
||||
//
|
||||
// # Field Masks and Oneof Fields
|
||||
//
|
||||
// Field masks treat fields in oneofs just as regular fields. Consider the
|
||||
// following message:
|
||||
//
|
||||
// message SampleMessage {
|
||||
// oneof test_oneof {
|
||||
// string name = 4;
|
||||
// SubMessage sub_message = 9;
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// The field mask can be:
|
||||
//
|
||||
// mask {
|
||||
// paths: "name"
|
||||
// }
|
||||
//
|
||||
// Or:
|
||||
//
|
||||
// mask {
|
||||
// paths: "sub_message"
|
||||
// }
|
||||
//
|
||||
// Note that oneof type names ("test_oneof" in this case) cannot be used in
|
||||
// paths.
|
||||
//
|
||||
// ## Field Mask Verification
|
||||
//
|
||||
// The implementation of any API method which has a FieldMask type field in the
|
||||
// request should verify the included field paths, and return an
|
||||
// `INVALID_ARGUMENT` error if any path is unmappable.
|
||||
message FieldMask {
|
||||
// The set of field mask paths.
|
||||
repeated string paths = 1;
|
||||
}
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "SourceContextProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/sourcecontextpb";
|
||||
|
||||
// `SourceContext` represents information about the source of a
|
||||
// protobuf element, like the file in which it is defined.
|
||||
message SourceContext {
|
||||
// The path-qualified name of the .proto file that contained the associated
|
||||
// protobuf element. For example: `"google/protobuf/source_context.proto"`.
|
||||
string file_name = 1;
|
||||
}
|
||||
|
|
@ -1,95 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/structpb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "StructProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
|
||||
// `Struct` represents a structured data value, consisting of fields
|
||||
// which map to dynamically typed values. In some languages, `Struct`
|
||||
// might be supported by a native representation. For example, in
|
||||
// scripting languages like JS a struct is represented as an
|
||||
// object. The details of that representation are described together
|
||||
// with the proto support for the language.
|
||||
//
|
||||
// The JSON representation for `Struct` is JSON object.
|
||||
message Struct {
|
||||
// Unordered map of dynamically typed values.
|
||||
map<string, Value> fields = 1;
|
||||
}
|
||||
|
||||
// `Value` represents a dynamically typed value which can be either
|
||||
// null, a number, a string, a boolean, a recursive struct value, or a
|
||||
// list of values. A producer of value is expected to set one of these
|
||||
// variants. Absence of any variant indicates an error.
|
||||
//
|
||||
// The JSON representation for `Value` is JSON value.
|
||||
message Value {
|
||||
// The kind of value.
|
||||
oneof kind {
|
||||
// Represents a null value.
|
||||
NullValue null_value = 1;
|
||||
// Represents a double value.
|
||||
double number_value = 2;
|
||||
// Represents a string value.
|
||||
string string_value = 3;
|
||||
// Represents a boolean value.
|
||||
bool bool_value = 4;
|
||||
// Represents a structured value.
|
||||
Struct struct_value = 5;
|
||||
// Represents a repeated `Value`.
|
||||
ListValue list_value = 6;
|
||||
}
|
||||
}
|
||||
|
||||
// `NullValue` is a singleton enumeration to represent the null value for the
|
||||
// `Value` type union.
|
||||
//
|
||||
// The JSON representation for `NullValue` is JSON `null`.
|
||||
enum NullValue {
|
||||
// Null value.
|
||||
NULL_VALUE = 0;
|
||||
}
|
||||
|
||||
// `ListValue` is a wrapper around a repeated field of values.
|
||||
//
|
||||
// The JSON representation for `ListValue` is JSON array.
|
||||
message ListValue {
|
||||
// Repeated field of dynamically typed values.
|
||||
repeated Value values = 1;
|
||||
}
|
||||
|
|
@ -1,303 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Test schema for proto2 messages. This test schema is used by:
|
||||
//
|
||||
// - conformance tests
|
||||
//
|
||||
|
||||
// LINT: ALLOW_GROUPS
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package protobuf_test_messages.proto2;
|
||||
|
||||
option java_package = "com.google.protobuf_test_messages.proto2";
|
||||
option objc_class_prefix = "Proto2";
|
||||
|
||||
// This is the default, but we specify it here explicitly.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// This proto includes every type of field in both singular and repeated
|
||||
// forms.
|
||||
//
|
||||
// Also, crucially, all messages and enums in this file are eventually
|
||||
// submessages of this message. So for example, a fuzz test of TestAllTypes
|
||||
// could trigger bugs that occur in any message type in this file. We verify
|
||||
// this stays true in a unit test.
|
||||
message TestAllTypesProto2 {
|
||||
message NestedMessage {
|
||||
optional int32 a = 1;
|
||||
optional TestAllTypesProto2 corecursive = 2;
|
||||
}
|
||||
|
||||
enum NestedEnum {
|
||||
FOO = 0;
|
||||
BAR = 1;
|
||||
BAZ = 2;
|
||||
NEG = -1; // Intentionally negative.
|
||||
}
|
||||
|
||||
// Singular
|
||||
optional int32 optional_int32 = 1;
|
||||
optional int64 optional_int64 = 2;
|
||||
optional uint32 optional_uint32 = 3;
|
||||
optional uint64 optional_uint64 = 4;
|
||||
optional sint32 optional_sint32 = 5;
|
||||
optional sint64 optional_sint64 = 6;
|
||||
optional fixed32 optional_fixed32 = 7;
|
||||
optional fixed64 optional_fixed64 = 8;
|
||||
optional sfixed32 optional_sfixed32 = 9;
|
||||
optional sfixed64 optional_sfixed64 = 10;
|
||||
optional float optional_float = 11;
|
||||
optional double optional_double = 12;
|
||||
optional bool optional_bool = 13;
|
||||
optional string optional_string = 14;
|
||||
optional bytes optional_bytes = 15;
|
||||
|
||||
optional NestedMessage optional_nested_message = 18;
|
||||
optional ForeignMessageProto2 optional_foreign_message = 19;
|
||||
|
||||
optional NestedEnum optional_nested_enum = 21;
|
||||
optional ForeignEnumProto2 optional_foreign_enum = 22;
|
||||
|
||||
optional string optional_string_piece = 24 [ctype = STRING_PIECE];
|
||||
optional string optional_cord = 25 [ctype = CORD];
|
||||
|
||||
optional TestAllTypesProto2 recursive_message = 27;
|
||||
|
||||
// Repeated
|
||||
repeated int32 repeated_int32 = 31;
|
||||
repeated int64 repeated_int64 = 32;
|
||||
repeated uint32 repeated_uint32 = 33;
|
||||
repeated uint64 repeated_uint64 = 34;
|
||||
repeated sint32 repeated_sint32 = 35;
|
||||
repeated sint64 repeated_sint64 = 36;
|
||||
repeated fixed32 repeated_fixed32 = 37;
|
||||
repeated fixed64 repeated_fixed64 = 38;
|
||||
repeated sfixed32 repeated_sfixed32 = 39;
|
||||
repeated sfixed64 repeated_sfixed64 = 40;
|
||||
repeated float repeated_float = 41;
|
||||
repeated double repeated_double = 42;
|
||||
repeated bool repeated_bool = 43;
|
||||
repeated string repeated_string = 44;
|
||||
repeated bytes repeated_bytes = 45;
|
||||
|
||||
repeated NestedMessage repeated_nested_message = 48;
|
||||
repeated ForeignMessageProto2 repeated_foreign_message = 49;
|
||||
|
||||
repeated NestedEnum repeated_nested_enum = 51;
|
||||
repeated ForeignEnumProto2 repeated_foreign_enum = 52;
|
||||
|
||||
repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
|
||||
repeated string repeated_cord = 55 [ctype = CORD];
|
||||
|
||||
// Packed
|
||||
repeated int32 packed_int32 = 75 [packed = true];
|
||||
repeated int64 packed_int64 = 76 [packed = true];
|
||||
repeated uint32 packed_uint32 = 77 [packed = true];
|
||||
repeated uint64 packed_uint64 = 78 [packed = true];
|
||||
repeated sint32 packed_sint32 = 79 [packed = true];
|
||||
repeated sint64 packed_sint64 = 80 [packed = true];
|
||||
repeated fixed32 packed_fixed32 = 81 [packed = true];
|
||||
repeated fixed64 packed_fixed64 = 82 [packed = true];
|
||||
repeated sfixed32 packed_sfixed32 = 83 [packed = true];
|
||||
repeated sfixed64 packed_sfixed64 = 84 [packed = true];
|
||||
repeated float packed_float = 85 [packed = true];
|
||||
repeated double packed_double = 86 [packed = true];
|
||||
repeated bool packed_bool = 87 [packed = true];
|
||||
repeated NestedEnum packed_nested_enum = 88 [packed = true];
|
||||
|
||||
// Unpacked
|
||||
repeated int32 unpacked_int32 = 89 [packed = false];
|
||||
repeated int64 unpacked_int64 = 90 [packed = false];
|
||||
repeated uint32 unpacked_uint32 = 91 [packed = false];
|
||||
repeated uint64 unpacked_uint64 = 92 [packed = false];
|
||||
repeated sint32 unpacked_sint32 = 93 [packed = false];
|
||||
repeated sint64 unpacked_sint64 = 94 [packed = false];
|
||||
repeated fixed32 unpacked_fixed32 = 95 [packed = false];
|
||||
repeated fixed64 unpacked_fixed64 = 96 [packed = false];
|
||||
repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
|
||||
repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
|
||||
repeated float unpacked_float = 99 [packed = false];
|
||||
repeated double unpacked_double = 100 [packed = false];
|
||||
repeated bool unpacked_bool = 101 [packed = false];
|
||||
repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
|
||||
|
||||
// Map
|
||||
map<int32, int32> map_int32_int32 = 56;
|
||||
map<int64, int64> map_int64_int64 = 57;
|
||||
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||
map<int32, float> map_int32_float = 66;
|
||||
map<int32, double> map_int32_double = 67;
|
||||
map<bool, bool> map_bool_bool = 68;
|
||||
map<string, string> map_string_string = 69;
|
||||
map<string, bytes> map_string_bytes = 70;
|
||||
map<string, NestedMessage> map_string_nested_message = 71;
|
||||
map<string, ForeignMessageProto2> map_string_foreign_message = 72;
|
||||
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||
map<string, ForeignEnumProto2> map_string_foreign_enum = 74;
|
||||
|
||||
oneof oneof_field {
|
||||
uint32 oneof_uint32 = 111;
|
||||
NestedMessage oneof_nested_message = 112;
|
||||
string oneof_string = 113;
|
||||
bytes oneof_bytes = 114;
|
||||
bool oneof_bool = 115;
|
||||
uint64 oneof_uint64 = 116;
|
||||
float oneof_float = 117;
|
||||
double oneof_double = 118;
|
||||
NestedEnum oneof_enum = 119;
|
||||
}
|
||||
|
||||
// extensions
|
||||
extensions 120 to 200;
|
||||
|
||||
// groups
|
||||
optional group Data = 201 {
|
||||
optional int32 group_int32 = 202;
|
||||
optional uint32 group_uint32 = 203;
|
||||
}
|
||||
|
||||
// default values
|
||||
optional int32 default_int32 = 241 [default = -123456789];
|
||||
optional int64 default_int64 = 242 [default = -9123456789123456789];
|
||||
optional uint32 default_uint32 = 243 [default = 2123456789];
|
||||
optional uint64 default_uint64 = 244 [default = 10123456789123456789];
|
||||
optional sint32 default_sint32 = 245 [default = -123456789];
|
||||
optional sint64 default_sint64 = 246 [default = -9123456789123456789];
|
||||
optional fixed32 default_fixed32 = 247 [default = 2123456789];
|
||||
optional fixed64 default_fixed64 = 248 [default = 10123456789123456789];
|
||||
optional sfixed32 default_sfixed32 = 249 [default = -123456789];
|
||||
optional sfixed64 default_sfixed64 = 250 [default = -9123456789123456789];
|
||||
optional float default_float = 251 [default = 9e9];
|
||||
optional double default_double = 252 [default = 7e22];
|
||||
optional bool default_bool = 253 [default = true];
|
||||
optional string default_string = 254 [default = "Rosebud"];
|
||||
optional bytes default_bytes = 255 [default = "joshua"];
|
||||
|
||||
// Test field-name-to-JSON-name convention.
|
||||
// (protobuf says names can be any valid C/C++ identifier.)
|
||||
optional int32 fieldname1 = 401;
|
||||
optional int32 field_name2 = 402;
|
||||
optional int32 _field_name3 = 403;
|
||||
optional int32 field__name4_ = 404;
|
||||
optional int32 field0name5 = 405;
|
||||
optional int32 field_0_name6 = 406;
|
||||
optional int32 fieldName7 = 407;
|
||||
optional int32 FieldName8 = 408;
|
||||
optional int32 field_Name9 = 409;
|
||||
optional int32 Field_Name10 = 410;
|
||||
optional int32 FIELD_NAME11 = 411;
|
||||
optional int32 FIELD_name12 = 412;
|
||||
optional int32 __field_name13 = 413;
|
||||
optional int32 __Field_name14 = 414;
|
||||
optional int32 field__name15 = 415;
|
||||
optional int32 field__Name16 = 416;
|
||||
optional int32 field_name17__ = 417;
|
||||
optional int32 Field_name18__ = 418;
|
||||
|
||||
// Reserved for unknown fields test.
|
||||
reserved 1000 to 9999;
|
||||
|
||||
// message_set test case.
|
||||
message MessageSetCorrect {
|
||||
option message_set_wire_format = true;
|
||||
|
||||
extensions 4 to max;
|
||||
}
|
||||
|
||||
message MessageSetCorrectExtension1 {
|
||||
extend MessageSetCorrect {
|
||||
optional MessageSetCorrectExtension1 message_set_extension = 1547769;
|
||||
}
|
||||
optional string str = 25;
|
||||
}
|
||||
|
||||
message MessageSetCorrectExtension2 {
|
||||
extend MessageSetCorrect {
|
||||
optional MessageSetCorrectExtension2 message_set_extension = 4135312;
|
||||
}
|
||||
optional int32 i = 9;
|
||||
}
|
||||
}
|
||||
|
||||
message ForeignMessageProto2 {
|
||||
optional int32 c = 1;
|
||||
}
|
||||
|
||||
enum ForeignEnumProto2 {
|
||||
FOREIGN_FOO = 0;
|
||||
FOREIGN_BAR = 1;
|
||||
FOREIGN_BAZ = 2;
|
||||
}
|
||||
|
||||
extend TestAllTypesProto2 {
|
||||
optional int32 extension_int32 = 120;
|
||||
}
|
||||
|
||||
message UnknownToTestAllTypes {
|
||||
optional int32 optional_int32 = 1001;
|
||||
optional string optional_string = 1002;
|
||||
optional ForeignMessageProto2 nested_message = 1003;
|
||||
optional group OptionalGroup = 1004 {
|
||||
optional int32 a = 1;
|
||||
}
|
||||
optional bool optional_bool = 1006;
|
||||
repeated int32 repeated_int32 = 1011;
|
||||
}
|
||||
|
||||
message NullHypothesisProto2 {}
|
||||
|
||||
message EnumOnlyProto2 {
|
||||
enum Bool {
|
||||
kFalse = 0;
|
||||
kTrue = 1;
|
||||
}
|
||||
}
|
||||
|
||||
message OneStringProto2 {
|
||||
optional string data = 1;
|
||||
}
|
||||
|
||||
message ProtoWithKeywords {
|
||||
optional int32 inline = 1;
|
||||
// optional string concept = 2;
|
||||
// repeated string requires = 3;
|
||||
}
|
||||
|
|
@ -1,288 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Test schema for proto3 messages. This test schema is used by:
|
||||
//
|
||||
// - benchmarks
|
||||
// - fuzz tests
|
||||
// - conformance tests
|
||||
//
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package protobuf_test_messages.proto3;
|
||||
|
||||
option java_package = "com.google.protobuf_test_messages.proto3";
|
||||
option objc_class_prefix = "Proto3";
|
||||
|
||||
// This is the default, but we specify it here explicitly.
|
||||
option optimize_for = SPEED;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/duration.proto";
|
||||
import "google/protobuf/field_mask.proto";
|
||||
import "google/protobuf/struct.proto";
|
||||
import "google/protobuf/timestamp.proto";
|
||||
import "google/protobuf/wrappers.proto";
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
|
||||
// This proto includes every type of field in both singular and repeated
|
||||
// forms.
|
||||
//
|
||||
// Also, crucially, all messages and enums in this file are eventually
|
||||
// submessages of this message. So for example, a fuzz test of TestAllTypes
|
||||
// could trigger bugs that occur in any message type in this file. We verify
|
||||
// this stays true in a unit test.
|
||||
message TestAllTypesProto3 {
|
||||
message NestedMessage {
|
||||
int32 a = 1;
|
||||
TestAllTypesProto3 corecursive = 2;
|
||||
}
|
||||
|
||||
enum NestedEnum {
|
||||
FOO = 0;
|
||||
BAR = 1;
|
||||
BAZ = 2;
|
||||
NEG = -1; // Intentionally negative.
|
||||
}
|
||||
|
||||
enum AliasedEnum {
|
||||
option allow_alias = true;
|
||||
|
||||
ALIAS_FOO = 0;
|
||||
ALIAS_BAR = 1;
|
||||
ALIAS_BAZ = 2;
|
||||
MOO = 2;
|
||||
moo = 2;
|
||||
bAz = 2;
|
||||
}
|
||||
|
||||
// Singular
|
||||
int32 optional_int32 = 1;
|
||||
int64 optional_int64 = 2;
|
||||
uint32 optional_uint32 = 3;
|
||||
uint64 optional_uint64 = 4;
|
||||
sint32 optional_sint32 = 5;
|
||||
sint64 optional_sint64 = 6;
|
||||
fixed32 optional_fixed32 = 7;
|
||||
fixed64 optional_fixed64 = 8;
|
||||
sfixed32 optional_sfixed32 = 9;
|
||||
sfixed64 optional_sfixed64 = 10;
|
||||
float optional_float = 11;
|
||||
double optional_double = 12;
|
||||
bool optional_bool = 13;
|
||||
string optional_string = 14;
|
||||
bytes optional_bytes = 15;
|
||||
|
||||
NestedMessage optional_nested_message = 18;
|
||||
ForeignMessage optional_foreign_message = 19;
|
||||
|
||||
NestedEnum optional_nested_enum = 21;
|
||||
ForeignEnum optional_foreign_enum = 22;
|
||||
AliasedEnum optional_aliased_enum = 23;
|
||||
|
||||
string optional_string_piece = 24 [ctype = STRING_PIECE];
|
||||
string optional_cord = 25 [ctype = CORD];
|
||||
|
||||
TestAllTypesProto3 recursive_message = 27;
|
||||
|
||||
// Repeated
|
||||
repeated int32 repeated_int32 = 31;
|
||||
repeated int64 repeated_int64 = 32;
|
||||
repeated uint32 repeated_uint32 = 33;
|
||||
repeated uint64 repeated_uint64 = 34;
|
||||
repeated sint32 repeated_sint32 = 35;
|
||||
repeated sint64 repeated_sint64 = 36;
|
||||
repeated fixed32 repeated_fixed32 = 37;
|
||||
repeated fixed64 repeated_fixed64 = 38;
|
||||
repeated sfixed32 repeated_sfixed32 = 39;
|
||||
repeated sfixed64 repeated_sfixed64 = 40;
|
||||
repeated float repeated_float = 41;
|
||||
repeated double repeated_double = 42;
|
||||
repeated bool repeated_bool = 43;
|
||||
repeated string repeated_string = 44;
|
||||
repeated bytes repeated_bytes = 45;
|
||||
|
||||
repeated NestedMessage repeated_nested_message = 48;
|
||||
repeated ForeignMessage repeated_foreign_message = 49;
|
||||
|
||||
repeated NestedEnum repeated_nested_enum = 51;
|
||||
repeated ForeignEnum repeated_foreign_enum = 52;
|
||||
|
||||
repeated string repeated_string_piece = 54 [ctype = STRING_PIECE];
|
||||
repeated string repeated_cord = 55 [ctype = CORD];
|
||||
|
||||
// Packed
|
||||
repeated int32 packed_int32 = 75 [packed = true];
|
||||
repeated int64 packed_int64 = 76 [packed = true];
|
||||
repeated uint32 packed_uint32 = 77 [packed = true];
|
||||
repeated uint64 packed_uint64 = 78 [packed = true];
|
||||
repeated sint32 packed_sint32 = 79 [packed = true];
|
||||
repeated sint64 packed_sint64 = 80 [packed = true];
|
||||
repeated fixed32 packed_fixed32 = 81 [packed = true];
|
||||
repeated fixed64 packed_fixed64 = 82 [packed = true];
|
||||
repeated sfixed32 packed_sfixed32 = 83 [packed = true];
|
||||
repeated sfixed64 packed_sfixed64 = 84 [packed = true];
|
||||
repeated float packed_float = 85 [packed = true];
|
||||
repeated double packed_double = 86 [packed = true];
|
||||
repeated bool packed_bool = 87 [packed = true];
|
||||
repeated NestedEnum packed_nested_enum = 88 [packed = true];
|
||||
|
||||
// Unpacked
|
||||
repeated int32 unpacked_int32 = 89 [packed = false];
|
||||
repeated int64 unpacked_int64 = 90 [packed = false];
|
||||
repeated uint32 unpacked_uint32 = 91 [packed = false];
|
||||
repeated uint64 unpacked_uint64 = 92 [packed = false];
|
||||
repeated sint32 unpacked_sint32 = 93 [packed = false];
|
||||
repeated sint64 unpacked_sint64 = 94 [packed = false];
|
||||
repeated fixed32 unpacked_fixed32 = 95 [packed = false];
|
||||
repeated fixed64 unpacked_fixed64 = 96 [packed = false];
|
||||
repeated sfixed32 unpacked_sfixed32 = 97 [packed = false];
|
||||
repeated sfixed64 unpacked_sfixed64 = 98 [packed = false];
|
||||
repeated float unpacked_float = 99 [packed = false];
|
||||
repeated double unpacked_double = 100 [packed = false];
|
||||
repeated bool unpacked_bool = 101 [packed = false];
|
||||
repeated NestedEnum unpacked_nested_enum = 102 [packed = false];
|
||||
|
||||
// Map
|
||||
map<int32, int32> map_int32_int32 = 56;
|
||||
map<int64, int64> map_int64_int64 = 57;
|
||||
map<uint32, uint32> map_uint32_uint32 = 58;
|
||||
map<uint64, uint64> map_uint64_uint64 = 59;
|
||||
map<sint32, sint32> map_sint32_sint32 = 60;
|
||||
map<sint64, sint64> map_sint64_sint64 = 61;
|
||||
map<fixed32, fixed32> map_fixed32_fixed32 = 62;
|
||||
map<fixed64, fixed64> map_fixed64_fixed64 = 63;
|
||||
map<sfixed32, sfixed32> map_sfixed32_sfixed32 = 64;
|
||||
map<sfixed64, sfixed64> map_sfixed64_sfixed64 = 65;
|
||||
map<int32, float> map_int32_float = 66;
|
||||
map<int32, double> map_int32_double = 67;
|
||||
map<bool, bool> map_bool_bool = 68;
|
||||
map<string, string> map_string_string = 69;
|
||||
map<string, bytes> map_string_bytes = 70;
|
||||
map<string, NestedMessage> map_string_nested_message = 71;
|
||||
map<string, ForeignMessage> map_string_foreign_message = 72;
|
||||
map<string, NestedEnum> map_string_nested_enum = 73;
|
||||
map<string, ForeignEnum> map_string_foreign_enum = 74;
|
||||
|
||||
oneof oneof_field {
|
||||
uint32 oneof_uint32 = 111;
|
||||
NestedMessage oneof_nested_message = 112;
|
||||
string oneof_string = 113;
|
||||
bytes oneof_bytes = 114;
|
||||
bool oneof_bool = 115;
|
||||
uint64 oneof_uint64 = 116;
|
||||
float oneof_float = 117;
|
||||
double oneof_double = 118;
|
||||
NestedEnum oneof_enum = 119;
|
||||
google.protobuf.NullValue oneof_null_value = 120;
|
||||
}
|
||||
|
||||
// Well-known types
|
||||
google.protobuf.BoolValue optional_bool_wrapper = 201;
|
||||
google.protobuf.Int32Value optional_int32_wrapper = 202;
|
||||
google.protobuf.Int64Value optional_int64_wrapper = 203;
|
||||
google.protobuf.UInt32Value optional_uint32_wrapper = 204;
|
||||
google.protobuf.UInt64Value optional_uint64_wrapper = 205;
|
||||
google.protobuf.FloatValue optional_float_wrapper = 206;
|
||||
google.protobuf.DoubleValue optional_double_wrapper = 207;
|
||||
google.protobuf.StringValue optional_string_wrapper = 208;
|
||||
google.protobuf.BytesValue optional_bytes_wrapper = 209;
|
||||
|
||||
repeated google.protobuf.BoolValue repeated_bool_wrapper = 211;
|
||||
repeated google.protobuf.Int32Value repeated_int32_wrapper = 212;
|
||||
repeated google.protobuf.Int64Value repeated_int64_wrapper = 213;
|
||||
repeated google.protobuf.UInt32Value repeated_uint32_wrapper = 214;
|
||||
repeated google.protobuf.UInt64Value repeated_uint64_wrapper = 215;
|
||||
repeated google.protobuf.FloatValue repeated_float_wrapper = 216;
|
||||
repeated google.protobuf.DoubleValue repeated_double_wrapper = 217;
|
||||
repeated google.protobuf.StringValue repeated_string_wrapper = 218;
|
||||
repeated google.protobuf.BytesValue repeated_bytes_wrapper = 219;
|
||||
|
||||
google.protobuf.Duration optional_duration = 301;
|
||||
google.protobuf.Timestamp optional_timestamp = 302;
|
||||
google.protobuf.FieldMask optional_field_mask = 303;
|
||||
google.protobuf.Struct optional_struct = 304;
|
||||
google.protobuf.Any optional_any = 305;
|
||||
google.protobuf.Value optional_value = 306;
|
||||
google.protobuf.NullValue optional_null_value = 307;
|
||||
|
||||
repeated google.protobuf.Duration repeated_duration = 311;
|
||||
repeated google.protobuf.Timestamp repeated_timestamp = 312;
|
||||
repeated google.protobuf.FieldMask repeated_fieldmask = 313;
|
||||
repeated google.protobuf.Struct repeated_struct = 324;
|
||||
repeated google.protobuf.Any repeated_any = 315;
|
||||
repeated google.protobuf.Value repeated_value = 316;
|
||||
repeated google.protobuf.ListValue repeated_list_value = 317;
|
||||
|
||||
// Test field-name-to-JSON-name convention.
|
||||
// (protobuf says names can be any valid C/C++ identifier.)
|
||||
int32 fieldname1 = 401;
|
||||
int32 field_name2 = 402;
|
||||
int32 _field_name3 = 403;
|
||||
int32 field__name4_ = 404;
|
||||
int32 field0name5 = 405;
|
||||
int32 field_0_name6 = 406;
|
||||
int32 fieldName7 = 407;
|
||||
int32 FieldName8 = 408;
|
||||
int32 field_Name9 = 409;
|
||||
int32 Field_Name10 = 410;
|
||||
int32 FIELD_NAME11 = 411;
|
||||
int32 FIELD_name12 = 412;
|
||||
int32 __field_name13 = 413;
|
||||
int32 __Field_name14 = 414;
|
||||
int32 field__name15 = 415;
|
||||
int32 field__Name16 = 416;
|
||||
int32 field_name17__ = 417;
|
||||
int32 Field_name18__ = 418;
|
||||
|
||||
// Reserved for testing unknown fields
|
||||
reserved 501 to 510;
|
||||
}
|
||||
|
||||
message ForeignMessage {
|
||||
int32 c = 1;
|
||||
}
|
||||
|
||||
enum ForeignEnum {
|
||||
FOREIGN_FOO = 0;
|
||||
FOREIGN_BAR = 1;
|
||||
FOREIGN_BAZ = 2;
|
||||
}
|
||||
|
||||
message NullHypothesisProto3 {}
|
||||
|
||||
message EnumOnlyProto3 {
|
||||
enum Bool {
|
||||
kFalse = 0;
|
||||
kTrue = 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,144 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/timestamppb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "TimestampProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
|
||||
// A Timestamp represents a point in time independent of any time zone or local
|
||||
// calendar, encoded as a count of seconds and fractions of seconds at
|
||||
// nanosecond resolution. The count is relative to an epoch at UTC midnight on
|
||||
// January 1, 1970, in the proleptic Gregorian calendar which extends the
|
||||
// Gregorian calendar backwards to year one.
|
||||
//
|
||||
// All minutes are 60 seconds long. Leap seconds are "smeared" so that no leap
|
||||
// second table is needed for interpretation, using a [24-hour linear
|
||||
// smear](https://developers.google.com/time/smear).
|
||||
//
|
||||
// The range is from 0001-01-01T00:00:00Z to 9999-12-31T23:59:59.999999999Z. By
|
||||
// restricting to that range, we ensure that we can convert to and from [RFC
|
||||
// 3339](https://www.ietf.org/rfc/rfc3339.txt) date strings.
|
||||
//
|
||||
// # Examples
|
||||
//
|
||||
// Example 1: Compute Timestamp from POSIX `time()`.
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(time(NULL));
|
||||
// timestamp.set_nanos(0);
|
||||
//
|
||||
// Example 2: Compute Timestamp from POSIX `gettimeofday()`.
|
||||
//
|
||||
// struct timeval tv;
|
||||
// gettimeofday(&tv, NULL);
|
||||
//
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds(tv.tv_sec);
|
||||
// timestamp.set_nanos(tv.tv_usec * 1000);
|
||||
//
|
||||
// Example 3: Compute Timestamp from Win32 `GetSystemTimeAsFileTime()`.
|
||||
//
|
||||
// FILETIME ft;
|
||||
// GetSystemTimeAsFileTime(&ft);
|
||||
// UINT64 ticks = (((UINT64)ft.dwHighDateTime) << 32) | ft.dwLowDateTime;
|
||||
//
|
||||
// // A Windows tick is 100 nanoseconds. Windows epoch 1601-01-01T00:00:00Z
|
||||
// // is 11644473600 seconds before Unix epoch 1970-01-01T00:00:00Z.
|
||||
// Timestamp timestamp;
|
||||
// timestamp.set_seconds((INT64) ((ticks / 10000000) - 11644473600LL));
|
||||
// timestamp.set_nanos((INT32) ((ticks % 10000000) * 100));
|
||||
//
|
||||
// Example 4: Compute Timestamp from Java `System.currentTimeMillis()`.
|
||||
//
|
||||
// long millis = System.currentTimeMillis();
|
||||
//
|
||||
// Timestamp timestamp = Timestamp.newBuilder().setSeconds(millis / 1000)
|
||||
// .setNanos((int) ((millis % 1000) * 1000000)).build();
|
||||
//
|
||||
// Example 5: Compute Timestamp from Java `Instant.now()`.
|
||||
//
|
||||
// Instant now = Instant.now();
|
||||
//
|
||||
// Timestamp timestamp =
|
||||
// Timestamp.newBuilder().setSeconds(now.getEpochSecond())
|
||||
// .setNanos(now.getNano()).build();
|
||||
//
|
||||
// Example 6: Compute Timestamp from current time in Python.
|
||||
//
|
||||
// timestamp = Timestamp()
|
||||
// timestamp.GetCurrentTime()
|
||||
//
|
||||
// # JSON Mapping
|
||||
//
|
||||
// In JSON format, the Timestamp type is encoded as a string in the
|
||||
// [RFC 3339](https://www.ietf.org/rfc/rfc3339.txt) format. That is, the
|
||||
// format is "{year}-{month}-{day}T{hour}:{min}:{sec}[.{frac_sec}]Z"
|
||||
// where {year} is always expressed using four digits while {month}, {day},
|
||||
// {hour}, {min}, and {sec} are zero-padded to two digits each. The fractional
|
||||
// seconds, which can go up to 9 digits (i.e. up to 1 nanosecond resolution),
|
||||
// are optional. The "Z" suffix indicates the timezone ("UTC"); the timezone
|
||||
// is required. A proto3 JSON serializer should always use UTC (as indicated by
|
||||
// "Z") when printing the Timestamp type and a proto3 JSON parser should be
|
||||
// able to accept both UTC and other timezones (as indicated by an offset).
|
||||
//
|
||||
// For example, "2017-01-15T01:30:15.01Z" encodes 15.01 seconds past
|
||||
// 01:30 UTC on January 15, 2017.
|
||||
//
|
||||
// In JavaScript, one can convert a Date object to this format using the
|
||||
// standard
|
||||
// [toISOString()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString)
|
||||
// method. In Python, a standard `datetime.datetime` object can be converted
|
||||
// to this format using
|
||||
// [`strftime`](https://docs.python.org/2/library/time.html#time.strftime) with
|
||||
// the time format spec '%Y-%m-%dT%H:%M:%S.%fZ'. Likewise, in Java, one can use
|
||||
// the Joda Time's [`ISODateTimeFormat.dateTime()`](
|
||||
// http://www.joda.org/joda-time/apidocs/org/joda/time/format/ISODateTimeFormat.html#dateTime%2D%2D
|
||||
// ) to obtain a formatter capable of generating timestamps in this format.
|
||||
//
|
||||
message Timestamp {
|
||||
// Represents seconds of UTC time since Unix epoch
|
||||
// 1970-01-01T00:00:00Z. Must be from 0001-01-01T00:00:00Z to
|
||||
// 9999-12-31T23:59:59Z inclusive.
|
||||
int64 seconds = 1;
|
||||
|
||||
// Non-negative fractions of a second at nanosecond resolution. Negative
|
||||
// second values with fractions must still have non-negative nanos values
|
||||
// that count forward in time. Must be from 0 to 999,999,999
|
||||
// inclusive.
|
||||
int32 nanos = 2;
|
||||
}
|
||||
|
|
@ -1,187 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
import "google/protobuf/any.proto";
|
||||
import "google/protobuf/source_context.proto";
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "TypeProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
option go_package = "google.golang.org/protobuf/types/known/typepb";
|
||||
|
||||
// A protocol buffer message type.
|
||||
message Type {
|
||||
// The fully qualified message name.
|
||||
string name = 1;
|
||||
// The list of fields.
|
||||
repeated Field fields = 2;
|
||||
// The list of types appearing in `oneof` definitions in this type.
|
||||
repeated string oneofs = 3;
|
||||
// The protocol buffer options.
|
||||
repeated Option options = 4;
|
||||
// The source context.
|
||||
SourceContext source_context = 5;
|
||||
// The source syntax.
|
||||
Syntax syntax = 6;
|
||||
}
|
||||
|
||||
// A single field of a message type.
|
||||
message Field {
|
||||
// Basic field types.
|
||||
enum Kind {
|
||||
// Field type unknown.
|
||||
TYPE_UNKNOWN = 0;
|
||||
// Field type double.
|
||||
TYPE_DOUBLE = 1;
|
||||
// Field type float.
|
||||
TYPE_FLOAT = 2;
|
||||
// Field type int64.
|
||||
TYPE_INT64 = 3;
|
||||
// Field type uint64.
|
||||
TYPE_UINT64 = 4;
|
||||
// Field type int32.
|
||||
TYPE_INT32 = 5;
|
||||
// Field type fixed64.
|
||||
TYPE_FIXED64 = 6;
|
||||
// Field type fixed32.
|
||||
TYPE_FIXED32 = 7;
|
||||
// Field type bool.
|
||||
TYPE_BOOL = 8;
|
||||
// Field type string.
|
||||
TYPE_STRING = 9;
|
||||
// Field type group. Proto2 syntax only, and deprecated.
|
||||
TYPE_GROUP = 10;
|
||||
// Field type message.
|
||||
TYPE_MESSAGE = 11;
|
||||
// Field type bytes.
|
||||
TYPE_BYTES = 12;
|
||||
// Field type uint32.
|
||||
TYPE_UINT32 = 13;
|
||||
// Field type enum.
|
||||
TYPE_ENUM = 14;
|
||||
// Field type sfixed32.
|
||||
TYPE_SFIXED32 = 15;
|
||||
// Field type sfixed64.
|
||||
TYPE_SFIXED64 = 16;
|
||||
// Field type sint32.
|
||||
TYPE_SINT32 = 17;
|
||||
// Field type sint64.
|
||||
TYPE_SINT64 = 18;
|
||||
}
|
||||
|
||||
// Whether a field is optional, required, or repeated.
|
||||
enum Cardinality {
|
||||
// For fields with unknown cardinality.
|
||||
CARDINALITY_UNKNOWN = 0;
|
||||
// For optional fields.
|
||||
CARDINALITY_OPTIONAL = 1;
|
||||
// For required fields. Proto2 syntax only.
|
||||
CARDINALITY_REQUIRED = 2;
|
||||
// For repeated fields.
|
||||
CARDINALITY_REPEATED = 3;
|
||||
}
|
||||
|
||||
// The field type.
|
||||
Kind kind = 1;
|
||||
// The field cardinality.
|
||||
Cardinality cardinality = 2;
|
||||
// The field number.
|
||||
int32 number = 3;
|
||||
// The field name.
|
||||
string name = 4;
|
||||
// The field type URL, without the scheme, for message or enumeration
|
||||
// types. Example: `"type.googleapis.com/google.protobuf.Timestamp"`.
|
||||
string type_url = 6;
|
||||
// The index of the field type in `Type.oneofs`, for message or enumeration
|
||||
// types. The first type has index 1; zero means the type is not in the list.
|
||||
int32 oneof_index = 7;
|
||||
// Whether to use alternative packed wire representation.
|
||||
bool packed = 8;
|
||||
// The protocol buffer options.
|
||||
repeated Option options = 9;
|
||||
// The field JSON name.
|
||||
string json_name = 10;
|
||||
// The string value of the default value of this field. Proto2 syntax only.
|
||||
string default_value = 11;
|
||||
}
|
||||
|
||||
// Enum type definition.
|
||||
message Enum {
|
||||
// Enum type name.
|
||||
string name = 1;
|
||||
// Enum value definitions.
|
||||
repeated EnumValue enumvalue = 2;
|
||||
// Protocol buffer options.
|
||||
repeated Option options = 3;
|
||||
// The source context.
|
||||
SourceContext source_context = 4;
|
||||
// The source syntax.
|
||||
Syntax syntax = 5;
|
||||
}
|
||||
|
||||
// Enum value definition.
|
||||
message EnumValue {
|
||||
// Enum value name.
|
||||
string name = 1;
|
||||
// Enum value number.
|
||||
int32 number = 2;
|
||||
// Protocol buffer options.
|
||||
repeated Option options = 3;
|
||||
}
|
||||
|
||||
// A protocol buffer option, which can be attached to a message, field,
|
||||
// enumeration, etc.
|
||||
message Option {
|
||||
// The option's name. For protobuf built-in options (options defined in
|
||||
// descriptor.proto), this is the short name. For example, `"map_entry"`.
|
||||
// For custom options, it should be the fully-qualified name. For example,
|
||||
// `"google.api.http"`.
|
||||
string name = 1;
|
||||
// The option's value packed in an Any message. If the value is a primitive,
|
||||
// the corresponding wrapper type defined in google/protobuf/wrappers.proto
|
||||
// should be used. If the value is an enum, it should be stored as an int32
|
||||
// value using the google.protobuf.Int32Value type.
|
||||
Any value = 2;
|
||||
}
|
||||
|
||||
// The syntax in which a protocol buffer element is defined.
|
||||
enum Syntax {
|
||||
// Syntax `proto2`.
|
||||
SYNTAX_PROTO2 = 0;
|
||||
// Syntax `proto3`.
|
||||
SYNTAX_PROTO3 = 1;
|
||||
}
|
||||
|
|
@ -1,123 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
//
|
||||
// Wrappers for primitive (non-message) types. These types are useful
|
||||
// for embedding primitives in the `google.protobuf.Any` type and for places
|
||||
// where we need to distinguish between the absence of a primitive
|
||||
// typed field and its default value.
|
||||
//
|
||||
// These wrappers have no meaningful use within repeated fields as they lack
|
||||
// the ability to detect presence on individual elements.
|
||||
// These wrappers have no meaningful use within a map or a oneof since
|
||||
// individual entries of a map or fields of a oneof can already detect presence.
|
||||
|
||||
syntax = "proto3";
|
||||
|
||||
package google.protobuf;
|
||||
|
||||
option cc_enable_arenas = true;
|
||||
option go_package = "google.golang.org/protobuf/types/known/wrapperspb";
|
||||
option java_package = "com.google.protobuf";
|
||||
option java_outer_classname = "WrappersProto";
|
||||
option java_multiple_files = true;
|
||||
option objc_class_prefix = "GPB";
|
||||
option csharp_namespace = "Google.Protobuf.WellKnownTypes";
|
||||
|
||||
// Wrapper message for `double`.
|
||||
//
|
||||
// The JSON representation for `DoubleValue` is JSON number.
|
||||
message DoubleValue {
|
||||
// The double value.
|
||||
double value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `float`.
|
||||
//
|
||||
// The JSON representation for `FloatValue` is JSON number.
|
||||
message FloatValue {
|
||||
// The float value.
|
||||
float value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `int64`.
|
||||
//
|
||||
// The JSON representation for `Int64Value` is JSON string.
|
||||
message Int64Value {
|
||||
// The int64 value.
|
||||
int64 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `uint64`.
|
||||
//
|
||||
// The JSON representation for `UInt64Value` is JSON string.
|
||||
message UInt64Value {
|
||||
// The uint64 value.
|
||||
uint64 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `int32`.
|
||||
//
|
||||
// The JSON representation for `Int32Value` is JSON number.
|
||||
message Int32Value {
|
||||
// The int32 value.
|
||||
int32 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `uint32`.
|
||||
//
|
||||
// The JSON representation for `UInt32Value` is JSON number.
|
||||
message UInt32Value {
|
||||
// The uint32 value.
|
||||
uint32 value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `bool`.
|
||||
//
|
||||
// The JSON representation for `BoolValue` is JSON `true` and `false`.
|
||||
message BoolValue {
|
||||
// The bool value.
|
||||
bool value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `string`.
|
||||
//
|
||||
// The JSON representation for `StringValue` is JSON string.
|
||||
message StringValue {
|
||||
// The string value.
|
||||
string value = 1;
|
||||
}
|
||||
|
||||
// Wrapper message for `bytes`.
|
||||
//
|
||||
// The JSON representation for `BytesValue` is JSON string.
|
||||
message BytesValue {
|
||||
// The bytes value.
|
||||
bytes value = 1;
|
||||
}
|
||||
|
|
@ -4,11 +4,11 @@ if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
|
|||
else()
|
||||
# else find installed yalantinglibs
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(coro_rpc_examples)
|
||||
project(struct_pb_examples)
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE "Release")
|
||||
endif()
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
# if you have install ylt
|
||||
|
|
@ -17,11 +17,8 @@ else()
|
|||
# else
|
||||
# include_directories(include)
|
||||
# include_directories(include/ylt/thirdparty)
|
||||
include(struct_pb_helper.cmake)
|
||||
endif()
|
||||
|
||||
find_package(Protobuf QUIET)
|
||||
if (Protobuf_FOUND)
|
||||
add_executable(struct_pb_tutorial tutorial.cpp)
|
||||
target_protos_struct_pb(struct_pb_tutorial PRIVATE addressbook.proto)
|
||||
endif()
|
||||
add_executable(struct_pb_examples
|
||||
main.cpp
|
||||
)
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package tutorial;
|
||||
|
||||
message Person {
|
||||
string name = 1;
|
||||
int32 id = 2;
|
||||
string email = 3;
|
||||
|
||||
enum PhoneType {
|
||||
MOBILE = 0;
|
||||
HOME = 1;
|
||||
WORK = 2;
|
||||
}
|
||||
|
||||
message PhoneNumber {
|
||||
string number = 1;
|
||||
PhoneType type = 2;
|
||||
}
|
||||
|
||||
repeated PhoneNumber phones = 4;
|
||||
}
|
||||
|
||||
message AddressBook {
|
||||
repeated Person people = 1;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
message SearchRequest {
|
||||
string query = 1;
|
||||
int32 page_number = 2;
|
||||
int32 result_per_page = 3;
|
||||
}
|
||||
|
||||
enum Corpus {
|
||||
CORPUS_UNSPECIFIED = 0;
|
||||
CORPUS_UNIVERSAL = 1;
|
||||
CORPUS_WEB = 2;
|
||||
CORPUS_IMAGES = 3;
|
||||
CORPUS_LOCAL = 4;
|
||||
CORPUS_NEWS = 5;
|
||||
CORPUS_PRODUCTS = 6;
|
||||
CORPUS_VIDEO = 7;
|
||||
}
|
||||
|
||||
message Outer { // Level 0
|
||||
message MiddleAA { // Level 1
|
||||
message Inner { // Level 2
|
||||
int64 ival = 1;
|
||||
bool booly = 2;
|
||||
}
|
||||
}
|
||||
message MiddleBB { // Level 1
|
||||
message Inner { // Level 2
|
||||
int32 ival = 1;
|
||||
bool booly = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
message SampleMessage {
|
||||
oneof test_oneof {
|
||||
string name = 4;
|
||||
SubMessage sub_message = 9;
|
||||
}
|
||||
}
|
||||
message SubMessage {
|
||||
int32 val = 1;
|
||||
}
|
||||
|
||||
message SampleMap {
|
||||
map<string, Project> projects = 3;
|
||||
}
|
||||
message Project {
|
||||
string name = 1;
|
||||
}
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
#include <cassert>
|
||||
#include <iostream>
|
||||
#include <ylt/struct_pb.hpp>
|
||||
|
||||
struct my_struct : struct_pb::base_impl<my_struct> {
|
||||
my_struct() = default;
|
||||
my_struct(int a, bool b, struct_pb::fixed64_t c) : x(a), y(b), z(c) {}
|
||||
int x;
|
||||
bool y;
|
||||
struct_pb::fixed64_t z;
|
||||
};
|
||||
REFLECTION(my_struct, x, y, z);
|
||||
|
||||
struct nest : struct_pb::base_impl<nest> {
|
||||
nest() = default;
|
||||
nest(std::string s, my_struct t, int v)
|
||||
: name(std::move(s)), value(t), var(v) {}
|
||||
std::string name;
|
||||
my_struct value;
|
||||
int var;
|
||||
};
|
||||
REFLECTION(nest, name, value, var);
|
||||
|
||||
struct person {
|
||||
int id;
|
||||
std::string name;
|
||||
int age;
|
||||
};
|
||||
REFLECTION(person, id, name, age);
|
||||
|
||||
int main() {
|
||||
nest v{"Hi", my_struct{1, false, {3}}, 5};
|
||||
std::string s;
|
||||
struct_pb::to_pb(v, s);
|
||||
|
||||
nest v2;
|
||||
struct_pb::from_pb(v2, s);
|
||||
assert(v.var == v2.var);
|
||||
assert(v.value.y == v2.value.y);
|
||||
assert(v.value.z == v2.value.z);
|
||||
|
||||
person p{1, "tom", 22};
|
||||
std::string str;
|
||||
struct_pb::to_pb(p, str);
|
||||
|
||||
person p1;
|
||||
struct_pb::from_pb(p1, str);
|
||||
assert(p.age == p1.age);
|
||||
assert(p.name == p1.name);
|
||||
assert(p.id == p1.id);
|
||||
|
||||
// dynamic reflection
|
||||
auto t = struct_pb::create_instance("nest");
|
||||
auto names = t->get_fields_name();
|
||||
bool r = (names == std::vector<std::string_view>{"name", "value", "var"});
|
||||
assert(r);
|
||||
|
||||
t->set_field_value("name", std::string("tom"));
|
||||
auto name = t->get_field_value<std::string>("name");
|
||||
assert(name == "tom");
|
||||
|
||||
auto d = dynamic_cast<nest *>(t.get());
|
||||
assert(d->name == "tom");
|
||||
|
||||
t->set_field_value<std::string>("name", "hello");
|
||||
auto &field_name = t->get_field_value<std::string>("name");
|
||||
assert(field_name == "hello");
|
||||
}
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "addressbook.struct_pb.h"
|
||||
void prompt_for_address(tutorial::Person& person) {
|
||||
std::cout << "==================================" << std::endl;
|
||||
std::cout << " Add People " << std::endl;
|
||||
std::cout << "==================================" << std::endl;
|
||||
std::cout << "Enter person ID number: ";
|
||||
std::cin >> person.id;
|
||||
std::cin.ignore(256, '\n');
|
||||
std::cout << "Enter name: ";
|
||||
std::getline(std::cin, person.name);
|
||||
std::cout << "Enter email address (blank for none): ";
|
||||
std::getline(std::cin, person.email);
|
||||
while (true) {
|
||||
std::cout << "Enter a phone number (or leave blank to finish): ";
|
||||
tutorial::Person::PhoneNumber phone_number;
|
||||
std::getline(std::cin, phone_number.number);
|
||||
if (phone_number.number.empty()) {
|
||||
break;
|
||||
}
|
||||
std::cout << "Is this a mobile, home, or work phone? ";
|
||||
std::string type;
|
||||
std::getline(std::cin, type);
|
||||
if (type == "mobile") {
|
||||
phone_number.type = tutorial::Person::PhoneType::MOBILE;
|
||||
}
|
||||
else if (type == "home") {
|
||||
phone_number.type = tutorial::Person::PhoneType::HOME;
|
||||
}
|
||||
else if (type == "work") {
|
||||
phone_number.type = tutorial::Person::PhoneType::WORK;
|
||||
}
|
||||
else {
|
||||
std::cout << "Unknown phone type: Using default." << std::endl;
|
||||
}
|
||||
person.phones.push_back(phone_number);
|
||||
}
|
||||
}
|
||||
void list_people(const tutorial::AddressBook& address_book) {
|
||||
std::cout << "==================================" << std::endl;
|
||||
std::cout << " List People " << std::endl;
|
||||
std::cout << "==================================" << std::endl;
|
||||
for (const auto& person : address_book.people) {
|
||||
std::cout << " Person ID: " << person.id << std::endl;
|
||||
std::cout << " Name: " << person.name << std::endl;
|
||||
if (!person.email.empty()) {
|
||||
std::cout << "E-mail address: " << person.email << std::endl;
|
||||
}
|
||||
for (const auto& phone : person.phones) {
|
||||
switch (phone.type) {
|
||||
case tutorial::Person::PhoneType::MOBILE:
|
||||
std::cout << "Mobile phone #: ";
|
||||
break;
|
||||
case tutorial::Person::PhoneType::HOME:
|
||||
std::cout << " Home phone #: ";
|
||||
break;
|
||||
case tutorial::Person::PhoneType::WORK:
|
||||
std::cout << " Work phone #: ";
|
||||
break;
|
||||
}
|
||||
std::cout << phone.number << std::endl;
|
||||
}
|
||||
}
|
||||
}
|
||||
int main(int argc, char* argv[]) {
|
||||
if (argc != 2) {
|
||||
std::cerr << "Usage: " << argv[0] << " ADDRESS_BOOK_FILE" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
tutorial::AddressBook address_book;
|
||||
std::fstream input(argv[1], std::ios::in | std::ios::binary);
|
||||
if (!input) {
|
||||
std::cout << argv[1] << ": File not found. Creating a new file."
|
||||
<< std::endl;
|
||||
}
|
||||
else {
|
||||
input.seekg(0, input.end);
|
||||
int length = input.tellg();
|
||||
input.seekg(0, input.beg);
|
||||
std::string buffer;
|
||||
buffer.resize(length);
|
||||
input.read(buffer.data(), buffer.size());
|
||||
input.close();
|
||||
bool ok = struct_pb::deserialize_to(address_book, buffer);
|
||||
if (!ok) {
|
||||
std::cerr << "Failed to parse address book." << std::endl;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
list_people(address_book);
|
||||
address_book.people.emplace_back();
|
||||
prompt_for_address(address_book.people.back());
|
||||
std::fstream output(argv[1],
|
||||
std::ios::out | std::ios::trunc | std::ios::binary);
|
||||
std::string buffer = struct_pb::serialize<std::string>(address_book);
|
||||
output.write(buffer.data(), buffer.size());
|
||||
output.close();
|
||||
list_people(address_book);
|
||||
std::cout << "Done!!!" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -1,18 +0,0 @@
|
|||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/bin)
|
||||
find_package(Protobuf QUIET)
|
||||
if (Protobuf_FOUND)
|
||||
file(GLOB SRCS "*.cpp" "*.h")
|
||||
add_executable(protoc-gen-struct_pb ${SRCS})
|
||||
target_link_libraries(protoc-gen-struct_pb PUBLIC protobuf::libprotoc protobuf::libprotobuf)
|
||||
install(
|
||||
TARGETS protoc-gen-struct_pb
|
||||
LIBRARY DESTINATION lib
|
||||
ARCHIVE DESTINATION lib
|
||||
RUNTIME DESTINATION bin
|
||||
)
|
||||
else ()
|
||||
message(STATUS "struct_pb is skipped. To build struct_pb protoc plugin, you must install libprotoc first\n"
|
||||
|
||||
"see https://alibaba.github.io/yalantinglibs/en/struct_pb/struct_pb_generating_your_struct.html"
|
||||
)
|
||||
endif ()
|
||||
|
|
@ -1,328 +0,0 @@
|
|||
#include "EnumFieldGenerator.h"
|
||||
|
||||
#include "helpers.hpp"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
EnumFieldGenerator::EnumFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options)
|
||||
: FieldGenerator(descriptor, options) {}
|
||||
std::string EnumFieldGenerator::cpp_type_name() const {
|
||||
auto name = qualified_enum_name(d_->enum_type(), options_);
|
||||
if (is_optional()) {
|
||||
return "std::optional<" + name + ">";
|
||||
}
|
||||
return name;
|
||||
}
|
||||
void EnumFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (is_optional()) {
|
||||
format("if ($1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
generate_calculate_size_only(p, value + ".value()");
|
||||
format(";\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
{"value", value},
|
||||
{"default_value", default_value()},
|
||||
},
|
||||
R"(
|
||||
if ($value$ != $default_value$) {
|
||||
total += $tag_sz$ + )");
|
||||
generate_calculate_size_only(p, value);
|
||||
p->Print(R"(;
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
},
|
||||
R"(
|
||||
total += $tag_sz$ + )");
|
||||
generate_calculate_size_only(p, value);
|
||||
p->Print(R"(;
|
||||
}
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
void EnumFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
// auto v = p->WithVars({{"tag", calculate_tag(d_)}, {"value", value}});
|
||||
if (is_optional()) {
|
||||
p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"(
|
||||
if ($value$.has_value()) {
|
||||
)");
|
||||
generate_serialization_only(p, value + ".value()");
|
||||
p->Print(R"(
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
p->Print({{"tag", calculate_tag_str(d_)},
|
||||
{"value", value},
|
||||
{"default_value", default_value()}},
|
||||
R"(
|
||||
if ($value$ != $default_value$) {
|
||||
)");
|
||||
generate_serialization_only(p, value);
|
||||
p->Print(R"(
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void EnumFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"tag", calculate_tag_str(d_)}, {"value", value}}, R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
serialize_varint(data, pos, size, static_cast<uint64_t>($value$));
|
||||
)");
|
||||
}
|
||||
void EnumFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print(
|
||||
{
|
||||
{"tag", calculate_tag_str(d_)},
|
||||
{"value", value},
|
||||
},
|
||||
R"(
|
||||
case $tag$: {
|
||||
)");
|
||||
generate_deserialization_only(p, value);
|
||||
p->Print(R"(
|
||||
break;
|
||||
}
|
||||
)");
|
||||
}
|
||||
void EnumFieldGenerator::generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &max_size) const {
|
||||
auto enum_name = qualified_enum_name(d_->enum_type(), options_);
|
||||
p->Print(
|
||||
{{"enum_name", enum_name}, {"output", output}, {"max_size", max_size}},
|
||||
R"(
|
||||
uint64_t enum_val_tmp{};
|
||||
ok = deserialize_varint(data, pos, $max_size$, enum_val_tmp);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
$output$ = static_cast<$enum_name$>(enum_val_tmp);
|
||||
)");
|
||||
}
|
||||
RepeatedEnumFieldGenerator::RepeatedEnumFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: FieldGenerator(descriptor, options) {}
|
||||
std::string RepeatedEnumFieldGenerator::cpp_type_name() const {
|
||||
return "std::vector<" + qualified_enum_name(d_->enum_type(), options_) + ">";
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
if (can_ignore_default_value) {
|
||||
if (is_packed()) {
|
||||
p->Print({{"value", value}}, R"(
|
||||
if (!$value$.empty()) { // packed
|
||||
)");
|
||||
generate_calculate_size_only(p, value, "sz");
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
},
|
||||
R"(
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print({{"value", value}}, R"(
|
||||
if (!$value$.empty()) { // unpacked
|
||||
)");
|
||||
generate_calculate_size_only(p, value, "sz");
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
},
|
||||
R"(
|
||||
total += sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (is_packed()) {
|
||||
generate_calculate_size_only(p, value, "sz");
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
},
|
||||
R"(
|
||||
// packed
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
)");
|
||||
}
|
||||
else {
|
||||
generate_calculate_size_only(p, value, "sz");
|
||||
p->Print(
|
||||
R"(
|
||||
// unpacked
|
||||
total += sz;
|
||||
)");
|
||||
}
|
||||
}
|
||||
}
|
||||
void RepeatedEnumFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
const std::string &output) const {
|
||||
if (is_packed()) {
|
||||
p->Print({{"value", value},
|
||||
{"output", output},
|
||||
{"tag_sz", calculate_tag_size(d_)}},
|
||||
R"(
|
||||
std::size_t $output$ = 0;
|
||||
for(const auto& v: $value$) {
|
||||
$output$ += calculate_varint_size(static_cast<uint64_t>(v));
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print({{"value", value},
|
||||
{"output", output},
|
||||
{"tag_sz", calculate_tag_size(d_, true)}},
|
||||
R"(
|
||||
std::size_t $output$ = 0;
|
||||
for(const auto& v: $value$) {
|
||||
$output$ += $tag_sz$;
|
||||
$output$ += calculate_varint_size(static_cast<uint64_t>(v));
|
||||
}
|
||||
)");
|
||||
}
|
||||
}
|
||||
|
||||
void RepeatedEnumFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
if (can_ignore_default_value) {
|
||||
p->Print({{"value", value}}, R"(
|
||||
if (!$value$.empty()) {
|
||||
)");
|
||||
generate_serialization_only(p, value);
|
||||
p->Print("}\n");
|
||||
}
|
||||
else {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
void RepeatedEnumFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
if (is_packed()) {
|
||||
p->Print({{"tag", std::to_string(calculate_tag(d_))}}, R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
)");
|
||||
generate_calculate_size_only(p, value, "sz");
|
||||
p->Print({{"value", value}},
|
||||
R"(
|
||||
serialize_varint(data, pos, size, sz);
|
||||
for(const auto& v: $value$) {
|
||||
serialize_varint(data, pos, size, static_cast<uint64_t>(v));
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print(
|
||||
{{"tag", std::to_string(calculate_tag(d_, true))}, {"value", value}},
|
||||
R"(
|
||||
for(const auto& v: $value$) {
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
serialize_varint(data, pos, size, static_cast<uint64_t>(v));
|
||||
}
|
||||
)");
|
||||
}
|
||||
}
|
||||
void RepeatedEnumFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
// generate packed
|
||||
p->Print({{"tag", packed_tag()},
|
||||
{"value", value},
|
||||
{"enum_name", qualified_enum_name(d_->enum_type(), options_)}
|
||||
|
||||
},
|
||||
R"(
|
||||
case $tag$: {
|
||||
uint64_t sz = 0;
|
||||
ok = deserialize_varint(data, pos, size, sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
std::size_t cur_max_sz = pos + sz;
|
||||
if (cur_max_sz > size) {
|
||||
return false;
|
||||
}
|
||||
while (pos < cur_max_sz) {
|
||||
uint64_t enum_val_tmp{};
|
||||
ok = deserialize_varint(data, pos, cur_max_sz, enum_val_tmp);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
$value$.push_back(static_cast<$enum_name$>(enum_val_tmp));
|
||||
}
|
||||
break;
|
||||
}
|
||||
)");
|
||||
p->Print({{"tag", unpacked_tag()},
|
||||
{"value", value},
|
||||
{"enum_name", qualified_enum_name(d_->enum_type(), options_)}},
|
||||
R"(
|
||||
case $tag$: {
|
||||
uint64_t enum_val_tmp{};
|
||||
ok = deserialize_varint(data, pos, size, enum_val_tmp);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
$value$.push_back(static_cast<$enum_name$>(enum_val_tmp));
|
||||
break;
|
||||
}
|
||||
)");
|
||||
}
|
||||
bool RepeatedEnumFieldGenerator::is_packed() const {
|
||||
return d_->is_packable() && d_->is_packed();
|
||||
}
|
||||
std::string RepeatedEnumFieldGenerator::packed_tag() const {
|
||||
uint32_t number = d_->number();
|
||||
uint32_t wire_type = 2;
|
||||
auto tag = number << 3 | wire_type;
|
||||
return std::to_string(tag);
|
||||
}
|
||||
std::string RepeatedEnumFieldGenerator::unpacked_tag() const {
|
||||
uint32_t number = d_->number();
|
||||
uint32_t wire_type = 0;
|
||||
auto tag = number << 3 | wire_type;
|
||||
return std::to_string(tag);
|
||||
}
|
||||
std::string EnumFieldGenerator::default_value() const {
|
||||
return qualified_enum_name(d_->enum_type(), options_) +
|
||||
"::" + d_->default_value_enum()->name();
|
||||
}
|
||||
void EnumFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"value", value}},
|
||||
"calculate_varint_size(static_cast<uint64_t>($value$))");
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class EnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
EnumFieldGenerator(const FieldDescriptor *descriptor, const Options &options);
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
void generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &max_size = "size") const;
|
||||
|
||||
private:
|
||||
std::string default_value() const;
|
||||
};
|
||||
class RepeatedEnumFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedEnumFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
const std::string &output) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
|
||||
private:
|
||||
bool is_packed() const;
|
||||
std::string packed_tag() const;
|
||||
std::string unpacked_tag() const;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#include "EnumGenerator.h"
|
||||
|
||||
#include "helpers.hpp"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
void EnumGenerator::generate(google::protobuf::io::Printer *p) {
|
||||
std::string enum_name = resolve_keyword(d_->name());
|
||||
p->Print({{"enum_name", enum_name}}, R"(
|
||||
enum class $enum_name$ {
|
||||
)");
|
||||
for (int j = 0; j < d_->value_count(); ++j) {
|
||||
auto v = d_->value(j);
|
||||
p->Print({{"name", resolve_keyword(v->name())},
|
||||
{"value", std::to_string(v->number())}},
|
||||
R"(
|
||||
$name$ = $value$,
|
||||
)");
|
||||
}
|
||||
p->Print(
|
||||
R"(
|
||||
};
|
||||
)");
|
||||
}
|
||||
void EnumGenerator::generate_definition(google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
format("enum class $1$: int {\n", resolve_keyword(d_->name()));
|
||||
format.indent();
|
||||
for (int i = 0; i < d_->value_count(); ++i) {
|
||||
auto value = resolve_keyword(d_->value(i)->name());
|
||||
auto number = d_->value(i)->number();
|
||||
format("$1$ = $2$,\n", value, number);
|
||||
}
|
||||
format.outdent();
|
||||
format("};\n");
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
#pragma once
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
#include <google/protobuf/descriptor.h>
|
||||
|
||||
#include "GeneratorBase.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
class EnumGenerator : public GeneratorBase {
|
||||
public:
|
||||
EnumGenerator(const google::protobuf::EnumDescriptor *d, Options options)
|
||||
: GeneratorBase(options), d_(d) {}
|
||||
void generate(google::protobuf::io::Printer *p);
|
||||
void generate_definition(google::protobuf::io::Printer *p);
|
||||
|
||||
private:
|
||||
const google::protobuf::EnumDescriptor *d_;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,557 +0,0 @@
|
|||
#include "FieldGenerator.h"
|
||||
|
||||
#include "EnumFieldGenerator.h"
|
||||
#include "MapFieldGenerator.h"
|
||||
#include "MessageFieldGenerator.h"
|
||||
#include "OneofFieldGenerator.h"
|
||||
#include "PrimitiveFieldGenerator.h"
|
||||
#include "StringFieldGenerator.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
#include "helpers.hpp"
|
||||
|
||||
using namespace google::protobuf;
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
bool is_varint(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_sint(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_sint32(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_enum(const FieldDescriptor *f) {
|
||||
return f->type() == FieldDescriptor::TYPE_ENUM;
|
||||
}
|
||||
bool is_bool(const FieldDescriptor *f) {
|
||||
return f->type() == FieldDescriptor::TYPE_BOOL;
|
||||
}
|
||||
bool is_i64(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_i32(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_string(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_STRING:
|
||||
case FieldDescriptor::TYPE_BYTES:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
bool is_message(const FieldDescriptor *f) {
|
||||
return f->type() == FieldDescriptor::TYPE_MESSAGE;
|
||||
}
|
||||
|
||||
bool is_group(const FieldDescriptor *f) {
|
||||
return f->type() == FieldDescriptor::TYPE_GROUP;
|
||||
}
|
||||
|
||||
bool is_number(const FieldDescriptor *f) {
|
||||
switch (f->type()) {
|
||||
case FieldDescriptor::TYPE_DOUBLE:
|
||||
case FieldDescriptor::TYPE_FLOAT:
|
||||
case FieldDescriptor::TYPE_INT64:
|
||||
case FieldDescriptor::TYPE_UINT64:
|
||||
case FieldDescriptor::TYPE_INT32:
|
||||
case FieldDescriptor::TYPE_FIXED64:
|
||||
case FieldDescriptor::TYPE_FIXED32:
|
||||
case FieldDescriptor::TYPE_BOOL:
|
||||
case FieldDescriptor::TYPE_UINT32:
|
||||
case FieldDescriptor::TYPE_ENUM:
|
||||
case FieldDescriptor::TYPE_SFIXED32:
|
||||
case FieldDescriptor::TYPE_SFIXED64:
|
||||
case FieldDescriptor::TYPE_SINT32:
|
||||
case FieldDescriptor::TYPE_SINT64:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated) {
|
||||
uint32_t number = f->number();
|
||||
uint32_t wire_type;
|
||||
if (f->is_repeated() && !ignore_repeated) {
|
||||
wire_type = 2;
|
||||
}
|
||||
else if (is_varint(f)) {
|
||||
wire_type = 0;
|
||||
}
|
||||
else if (is_i64(f)) {
|
||||
wire_type = 1;
|
||||
}
|
||||
else if (is_i32(f)) {
|
||||
wire_type = 5;
|
||||
}
|
||||
else {
|
||||
wire_type = 2;
|
||||
}
|
||||
return (number << 3) | wire_type;
|
||||
}
|
||||
|
||||
std::string calculate_tag_str(const FieldDescriptor *f, bool ignore_repeated) {
|
||||
return std::to_string(calculate_tag(f, ignore_repeated));
|
||||
}
|
||||
|
||||
std::size_t calculate_varint_size(uint64_t t) {
|
||||
std::size_t ret = 0;
|
||||
do {
|
||||
ret++;
|
||||
t >>= 7;
|
||||
} while (t != 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string calculate_tag_size(const FieldDescriptor *f, bool ignore_repeated) {
|
||||
auto tag = calculate_tag(f, ignore_repeated);
|
||||
auto tag_size = calculate_varint_size(tag);
|
||||
return std::to_string(tag_size);
|
||||
}
|
||||
|
||||
std::string get_comment(const FieldDescriptor *d_) {
|
||||
std::string comment;
|
||||
if (d_->has_optional_keyword()) {
|
||||
comment += "optional ";
|
||||
}
|
||||
if (d_->is_repeated()) {
|
||||
comment += "repeated ";
|
||||
}
|
||||
if (is_message(d_)) {
|
||||
comment += class_name(d_->message_type());
|
||||
}
|
||||
else {
|
||||
comment += d_->type_name();
|
||||
}
|
||||
comment += " ";
|
||||
comment += d_->name();
|
||||
comment += " = ";
|
||||
comment += std::to_string(d_->number());
|
||||
comment += ", tag = ";
|
||||
comment += std::to_string(calculate_tag(d_));
|
||||
return comment;
|
||||
}
|
||||
|
||||
void FieldGenerator::generate_definition(
|
||||
google::protobuf::io::Printer *p) const {
|
||||
p->Print(
|
||||
{
|
||||
{"type", cpp_type_name()},
|
||||
{"name", name()},
|
||||
{"pb_type", pb_type_name()},
|
||||
{"number", std::to_string(d_->number())},
|
||||
},
|
||||
R"($type$ $name$; // $pb_type$, field number = $number$
|
||||
)");
|
||||
}
|
||||
|
||||
std::string FieldGenerator::get_type_name() const {
|
||||
switch (d_->type()) {
|
||||
case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
|
||||
return "double";
|
||||
case google::protobuf::FieldDescriptor::TYPE_FLOAT:
|
||||
return "float";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT64:
|
||||
return "int64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED64:
|
||||
return "uint64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED32:
|
||||
return "uint32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT32:
|
||||
return "int32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_BOOL:
|
||||
return "bool";
|
||||
case google::protobuf::FieldDescriptor::TYPE_STRING:
|
||||
case google::protobuf::FieldDescriptor::TYPE_BYTES:
|
||||
return "std::string";
|
||||
case google::protobuf::FieldDescriptor::TYPE_MESSAGE: {
|
||||
auto m = d_->message_type();
|
||||
if (d_->is_map()) {
|
||||
auto key = m->field(0);
|
||||
auto value = m->field(1);
|
||||
std::string type_name = "std::map<";
|
||||
type_name += FieldGenerator(key, options_).get_type_name();
|
||||
type_name += ", ";
|
||||
type_name += FieldGenerator(value, options_).get_type_name();
|
||||
type_name += ">";
|
||||
return type_name;
|
||||
}
|
||||
else if (d_->is_repeated()) {
|
||||
if (is_message(d_)) {
|
||||
return qualified_class_name(d_->message_type(), options_);
|
||||
}
|
||||
else {
|
||||
return m->name();
|
||||
}
|
||||
}
|
||||
else {
|
||||
auto p = d_->containing_type();
|
||||
if (is_map_entry(p)) {
|
||||
return m->name();
|
||||
}
|
||||
else {
|
||||
return "std::unique_ptr<" +
|
||||
qualified_class_name(d_->message_type(), options_) + ">";
|
||||
}
|
||||
}
|
||||
}
|
||||
case google::protobuf::FieldDescriptor::TYPE_ENUM:
|
||||
return d_->enum_type()->name();
|
||||
case google::protobuf::FieldDescriptor::TYPE_GROUP:
|
||||
// workaround for group
|
||||
return "std::string";
|
||||
default: {
|
||||
return "not support now";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
// auto name = value.empty() ? "t." + this->name() : value;
|
||||
// auto tag = calculate_tag(d_);
|
||||
// auto v =
|
||||
// p->WithVars({{"name", name}, {"tag_size",
|
||||
// calculate_varint_size(tag)}});
|
||||
// std::string comment = get_comment(d_);
|
||||
// p->Print({{"comment", comment}}, R"(
|
||||
//// $comment$
|
||||
//)");
|
||||
// if (d_->has_optional_keyword() && !is_message(d_)) {
|
||||
// p->Print(R"(
|
||||
// if ($name$.has_value()) {
|
||||
//)");
|
||||
// generate_calculate_one(p, name + ".value()", false);
|
||||
// p->Print("}\n");
|
||||
// } else if (d_->is_repeated()) {
|
||||
// generate_calculate_vector(p);
|
||||
// } else {
|
||||
// generate_calculate_one(p, name, can_ignore_default_value);
|
||||
// }
|
||||
}
|
||||
|
||||
void FieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
// auto name = value.empty() ? "t." + this->name() : value;
|
||||
// auto tag = calculate_tag(d_);
|
||||
// auto v =
|
||||
// p->WithVars({{"name", name}, {"tag_size",
|
||||
// calculate_varint_size(tag)}});
|
||||
// auto comment = get_comment(d_);
|
||||
// p->Print({{"comment", comment}}, R"(
|
||||
//// $comment$
|
||||
//)");
|
||||
// if (is_optional()) {
|
||||
// p->Print(R"(
|
||||
// if ($name$.has_value()) {
|
||||
//)");
|
||||
// generate_serialize_one(p, name + ".value()", false);
|
||||
// p->Print("}\n");
|
||||
// } else if (d_->is_repeated()) {
|
||||
// generate_serialize_vector(p);
|
||||
// } else {
|
||||
// generate_serialize_one(p, name, can_ignore_default_value);
|
||||
// }
|
||||
}
|
||||
void FieldGenerator::generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const {}
|
||||
bool FieldGenerator::is_ptr() const {
|
||||
auto p = d_->containing_type();
|
||||
if (p && is_map_entry(p)) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
std::string FieldGenerator::name() const { return resolve_keyword(d_->name()); }
|
||||
bool FieldGenerator::is_optional() const {
|
||||
auto p = d_->containing_type();
|
||||
if (p && is_map_entry(p)) {
|
||||
return false;
|
||||
}
|
||||
// return d_->is_optional();
|
||||
// return d_->has_optional_keyword() && !is_message(d_);
|
||||
return d_->has_presence();
|
||||
}
|
||||
std::string FieldGenerator::qualified_name() const {
|
||||
if (is_message(d_)) {
|
||||
return qualified_class_name(d_->message_type(), options_);
|
||||
}
|
||||
else if (is_enum(d_)) {
|
||||
return qualified_enum_name(d_->enum_type(), options_);
|
||||
}
|
||||
else {
|
||||
return get_type_name();
|
||||
}
|
||||
}
|
||||
std::string FieldGenerator::pb_type_name() const { return d_->type_name(); }
|
||||
void FieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, bool can_ignore_default_value) const {
|
||||
auto oneof = d_->real_containing_oneof();
|
||||
if (oneof) {
|
||||
generate_calculate_size(p, "t." + resolve_keyword(oneof->name()),
|
||||
can_ignore_default_value);
|
||||
}
|
||||
else {
|
||||
generate_calculate_size(p, "t." + name(), can_ignore_default_value);
|
||||
}
|
||||
}
|
||||
void FieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, bool can_ignore_default_value) const {
|
||||
auto oneof = d_->real_containing_oneof();
|
||||
if (oneof) {
|
||||
generate_serialization(p, "t." + resolve_keyword(oneof->name()),
|
||||
can_ignore_default_value);
|
||||
}
|
||||
else {
|
||||
Formatter format(p);
|
||||
format("// ");
|
||||
generate_definition(p);
|
||||
generate_serialization(p, "t." + name(), can_ignore_default_value);
|
||||
}
|
||||
}
|
||||
void FieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p) const {
|
||||
auto oneof = d_->real_containing_oneof();
|
||||
if (oneof) {
|
||||
generate_deserialization(p, "t." + resolve_keyword(oneof->name()));
|
||||
}
|
||||
else {
|
||||
Formatter format(p);
|
||||
format("// ");
|
||||
generate_definition(p);
|
||||
generate_deserialization(p, "t." + name());
|
||||
}
|
||||
}
|
||||
std::string FieldGenerator::cpp_type_name() const {
|
||||
assert(false && "why?");
|
||||
return "???";
|
||||
}
|
||||
void OneofGenerator::generate_definition(google::protobuf::io::Printer *p) {
|
||||
p->Print(R"(std::variant<std::monostate
|
||||
)");
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
FieldGenerator fg(f, options_);
|
||||
std::string type_name = fg.get_type_name();
|
||||
if (is_message(f)) {
|
||||
type_name = qualified_class_name(f->message_type(), options_);
|
||||
type_name = "std::unique_ptr<" + type_name + ">";
|
||||
}
|
||||
else if (is_enum(f)) {
|
||||
type_name = qualified_enum_name(f->enum_type(), options_);
|
||||
}
|
||||
p->Print(
|
||||
{
|
||||
{"type", type_name},
|
||||
{"name", f->name()},
|
||||
{"pb_type", f->type_name()},
|
||||
{"number", std::to_string(f->number())},
|
||||
},
|
||||
R"(, $type$ // $pb_type$, field number = $number$
|
||||
)");
|
||||
}
|
||||
p->Print({{"name", name()}}, R"(> $name$;
|
||||
)");
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
if (is_message(f)) {
|
||||
MessageOneofFieldGenerator(f, options_).generate_setter_and_getter(p);
|
||||
}
|
||||
else if (is_string(f)) {
|
||||
StringOneofFieldGenerator(f, options_).generate_setter_and_getter(p);
|
||||
}
|
||||
else if (is_enum(f)) {
|
||||
EnumOneofFieldGenerator(f, options_).generate_setter_and_getter(p);
|
||||
}
|
||||
else {
|
||||
PrimitiveOneofFieldGenerator(f, options_).generate_setter_and_getter(p);
|
||||
}
|
||||
}
|
||||
}
|
||||
void OneofGenerator::generate_calculate_size(google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
format("{\n");
|
||||
format.indent();
|
||||
format("switch (t.$1$.index()) {\n", name());
|
||||
p->Print(R"(
|
||||
case 0: {
|
||||
// empty, do nothing
|
||||
break;
|
||||
}
|
||||
)");
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
format("case $1$: {\n", i + 1);
|
||||
format.indent();
|
||||
std::string value =
|
||||
"std::get<" + std::to_string(i + 1) + ">(t." + name() + ")";
|
||||
FieldGenerator(f, options_).generate_calculate_size(p, value, false);
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
format("}\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void OneofGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p,
|
||||
const google::protobuf::FieldDescriptor *f) {
|
||||
// auto index = get_index(f);
|
||||
// assert(index != 0);
|
||||
// auto v = p->WithVars({{"name", "t." + name()}, {"index", index}});
|
||||
// Formatter format(p);
|
||||
// format("if ($name$.index() == $index$) {\n");
|
||||
// format.indent();
|
||||
// std::string name = "std::get<";
|
||||
// name += std::to_string(index);
|
||||
// name += ">";
|
||||
// name += "(";
|
||||
// name += "t." + this->name();
|
||||
// name += ")";
|
||||
// FieldGenerator(f, options_).generate_serialization(p, name, false);
|
||||
// format.outdent();
|
||||
// format("}\n");
|
||||
}
|
||||
void OneofGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p,
|
||||
const google::protobuf::FieldDescriptor *f) {
|
||||
// auto index = get_index(f);
|
||||
// assert(index != 0);
|
||||
// auto v = p->WithVars({{"name", "t." + name()}, {"index", index}});
|
||||
// Formatter format(p);
|
||||
// FieldGenerator fg(f, options_);
|
||||
// std::string end =
|
||||
// "t." + name() + ".emplace<" + std::to_string(index) + ">(tmp);";
|
||||
// if (is_message(f)) {
|
||||
// auto type_name = qualified_class_name(f->message_type(), options_);
|
||||
// fg.generate_deserialization(
|
||||
// p, "tmp", type_name + "* tmp = new " + type_name + "();", end);
|
||||
// } else if (is_enum(f)) {
|
||||
// auto type_name = qualified_enum_name(f->enum_type(), options_);
|
||||
// fg.generate_deserialization(p, "tmp", type_name + " tmp{};", end);
|
||||
// } else {
|
||||
// fg.generate_deserialization(p, "tmp", fg.get_type_name() + " tmp{};",
|
||||
// end);
|
||||
// }
|
||||
}
|
||||
int OneofGenerator::get_index(
|
||||
const google::protobuf::FieldDescriptor *f) const {
|
||||
auto index = 0;
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto fd = d_->field(i);
|
||||
if (fd == f) {
|
||||
index = i + 1;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
}
|
||||
std::string OneofGenerator::name() const { return resolve_keyword(d_->name()); }
|
||||
FieldGenerator *FieldGeneratorMap::MakeGenerator(const FieldDescriptor *field,
|
||||
const Options &options) {
|
||||
if (field->is_repeated()) {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
if (field->is_map()) {
|
||||
return new MapFieldGenerator(field, options);
|
||||
}
|
||||
else {
|
||||
return new RepeatedMessageFieldGenerator(field, options);
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return new RepeatedStringFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new RepeatedEnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new RepeatedPrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
}
|
||||
else if (field->real_containing_oneof()) {
|
||||
return new OneofFieldGenerator(field, options);
|
||||
// switch (field->cpp_type()) {
|
||||
// case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
// return new MessageOneofFieldGenerator(field, options, scc_analyzer);
|
||||
// case FieldDescriptor::CPPTYPE_STRING:
|
||||
// return new StringOneofFieldGenerator(field, options);
|
||||
// case FieldDescriptor::CPPTYPE_ENUM:
|
||||
// return new EnumOneofFieldGenerator(field, options);
|
||||
// default:
|
||||
// return new PrimitiveOneofFieldGenerator(field, options);
|
||||
// }
|
||||
}
|
||||
else {
|
||||
switch (field->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE:
|
||||
return new MessageFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_STRING:
|
||||
return new StringFieldGenerator(field, options);
|
||||
case FieldDescriptor::CPPTYPE_ENUM:
|
||||
return new EnumFieldGenerator(field, options);
|
||||
default:
|
||||
return new PrimitiveFieldGenerator(field, options);
|
||||
}
|
||||
}
|
||||
}
|
||||
FieldGeneratorMap::FieldGeneratorMap(const Descriptor *descriptor,
|
||||
const Options &options)
|
||||
: descriptor_(descriptor), field_generators_(descriptor->field_count()) {
|
||||
// Construct all the FieldGenerators.
|
||||
for (int i = 0; i < descriptor->field_count(); i++) {
|
||||
field_generators_[i].reset(MakeGenerator(descriptor->field(i), options));
|
||||
}
|
||||
}
|
||||
const FieldGenerator &FieldGeneratorMap::get(
|
||||
const FieldDescriptor *field) const {
|
||||
return *field_generators_[field->index()];
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,90 +0,0 @@
|
|||
#pragma once
|
||||
#include "GeneratorBase.h"
|
||||
#include "helpers.hpp"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
class OneofGenerator;
|
||||
bool is_varint(const FieldDescriptor *f);
|
||||
bool is_sint(const FieldDescriptor *f);
|
||||
bool is_sint32(const FieldDescriptor *f);
|
||||
bool is_bool(const FieldDescriptor *f);
|
||||
bool is_i64(const FieldDescriptor *f);
|
||||
bool is_i32(const FieldDescriptor *f);
|
||||
uint32_t calculate_tag(const FieldDescriptor *f, bool ignore_repeated = false);
|
||||
std::string calculate_tag_str(const FieldDescriptor *f,
|
||||
bool ignore_repeated = false);
|
||||
std::string calculate_tag_size(const FieldDescriptor *f,
|
||||
bool ignore_repeated = false);
|
||||
class FieldGenerator : public GeneratorBase {
|
||||
public:
|
||||
FieldGenerator(const google::protobuf::FieldDescriptor *d,
|
||||
const Options &options)
|
||||
: GeneratorBase(options), d_(d) {}
|
||||
void generate_definition(google::protobuf::io::Printer *p) const;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
bool can_ignore_default_value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
bool can_ignore_default_value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p) const;
|
||||
|
||||
virtual void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const;
|
||||
virtual void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const;
|
||||
virtual void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
virtual std::string cpp_type_name() const;
|
||||
virtual std::string pb_type_name() const;
|
||||
|
||||
protected:
|
||||
std::string get_type_name() const;
|
||||
bool is_ptr() const;
|
||||
std::string name() const;
|
||||
bool is_optional() const;
|
||||
std::string qualified_name() const;
|
||||
|
||||
protected:
|
||||
const google::protobuf::FieldDescriptor *d_;
|
||||
friend class OneofGenerator;
|
||||
};
|
||||
class OneofGenerator : public GeneratorBase {
|
||||
public:
|
||||
OneofGenerator(const google::protobuf::OneofDescriptor *d,
|
||||
const Options &options)
|
||||
: GeneratorBase(options), d_(d) {}
|
||||
void generate_definition(google::protobuf::io::Printer *p);
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p);
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const google::protobuf::FieldDescriptor *f);
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const google::protobuf::FieldDescriptor *f);
|
||||
|
||||
private:
|
||||
int get_index(const google::protobuf::FieldDescriptor *f) const;
|
||||
std::string name() const;
|
||||
|
||||
private:
|
||||
const google::protobuf::OneofDescriptor *d_;
|
||||
};
|
||||
class MapFieldGenerator;
|
||||
class FieldGeneratorMap {
|
||||
public:
|
||||
FieldGeneratorMap(const Descriptor *descriptor, const Options &options);
|
||||
FieldGeneratorMap(const FieldGeneratorMap &) = delete;
|
||||
FieldGeneratorMap &operator=(const FieldGeneratorMap &) = delete;
|
||||
|
||||
const FieldGenerator &get(const FieldDescriptor *field) const;
|
||||
|
||||
private:
|
||||
const Descriptor *descriptor_;
|
||||
std::vector<std::unique_ptr<FieldGenerator>> field_generators_;
|
||||
|
||||
static FieldGenerator *MakeGenerator(const FieldDescriptor *field,
|
||||
const Options &options);
|
||||
friend class MapFieldGenerator;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,199 +0,0 @@
|
|||
#include "FileGenerator.h"
|
||||
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
|
||||
#include "EnumGenerator.h"
|
||||
#include "MessageGenerator.h"
|
||||
#include "helpers.hpp"
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::compiler;
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
FileGenerator::FileGenerator(const google::protobuf::FileDescriptor *file,
|
||||
Options options)
|
||||
: GeneratorBase(options), file_(file) {
|
||||
// std::vector<const Descriptor*> msgs = flatten_messages_in_file(file);
|
||||
for (int i = 0; i < file_->message_type_count(); ++i) {
|
||||
message_generators_.push_back(
|
||||
std::make_unique<MessageGenerator>(file_->message_type(i), options));
|
||||
}
|
||||
for (int i = 0; i < file->enum_type_count(); ++i) {
|
||||
enum_generators_.push_back(
|
||||
std::make_unique<EnumGenerator>(file->enum_type(i), options));
|
||||
}
|
||||
}
|
||||
|
||||
void FileGenerator::generate_enum_definitions(
|
||||
google::protobuf::io::Printer *p) {
|
||||
for (int i = 0; i < enum_generators_.size(); ++i) {
|
||||
enum_generators_[i]->generate_definition(p);
|
||||
}
|
||||
}
|
||||
void FileGenerator::generate_message_definitions(
|
||||
google::protobuf::io::Printer *p) {
|
||||
for (int i = 0; i < message_generators_.size(); ++i) {
|
||||
message_generators_[i]->generate_struct_definition(p);
|
||||
}
|
||||
}
|
||||
void FileGenerator::generate_shared_header_code(
|
||||
google::protobuf::io::Printer *p) {
|
||||
generate_fwd_decls(p);
|
||||
generate_enum_definitions(p);
|
||||
generate_message_definitions(p);
|
||||
}
|
||||
void FileGenerator::generate_header(google::protobuf::io::Printer *p) {
|
||||
p->Print(
|
||||
{{"filename", file_->name()}},
|
||||
R"(// Generated by the protocol buffer compiler (struct_pb). DO NOT EDIT!
|
||||
// source: $filename$
|
||||
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <type_traits>
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
|
||||
#include "ylt/struct_pb.hpp"
|
||||
)");
|
||||
|
||||
generate_dependency_includes(p);
|
||||
generate_ns_open(p);
|
||||
generate_shared_header_code(p);
|
||||
generate_ns_close(p);
|
||||
generate_message_struct_pb_func_definitions(p);
|
||||
p->Print("// clang-format on\n");
|
||||
}
|
||||
|
||||
void FileGenerator::generate_fwd_decls(google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
for (int i = 0; i < file_->message_type_count(); ++i) {
|
||||
auto m = file_->message_type(i);
|
||||
format("struct $1$;\n", resolve_keyword(m->name()));
|
||||
}
|
||||
}
|
||||
void FileGenerator::generate_dependency_includes(
|
||||
google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
for (int i = 0; i < file_->dependency_count(); ++i) {
|
||||
auto dep = file_->dependency(i);
|
||||
std::string basename = strip_proto(dep->name());
|
||||
std::string header_name = basename + ".struct_pb.h";
|
||||
format("#include \"$1$\"\n", header_name);
|
||||
}
|
||||
}
|
||||
void FileGenerator::generate_source(google::protobuf::io::Printer *p) {
|
||||
generate_message_struct_pb_func_source(p);
|
||||
}
|
||||
void FileGenerator::generate_message_struct_pb_func_definitions(
|
||||
google::protobuf::io::Printer *p) {
|
||||
std::vector<const Descriptor *> msgs = flatten_messages_in_file(file_);
|
||||
Formatter format(p);
|
||||
format("namespace struct_pb {\n");
|
||||
format("namespace internal {\n");
|
||||
for (auto msg : msgs) {
|
||||
auto name = qualified_class_name(msg, options_);
|
||||
format("// $1$\n", name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"std::size_t get_needed_size<$1$>(const $1$& t, const "
|
||||
"::struct_pb::UnknownFields& unknown_fields);\n",
|
||||
name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, "
|
||||
"const "
|
||||
"::struct_pb::UnknownFields& unknown_fields);\n",
|
||||
name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, "
|
||||
"::struct_pb::UnknownFields& unknown_fields);\n",
|
||||
name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"bool deserialize_to<$1$>($1$& t, const char* data, std::size_t "
|
||||
"size);\n",
|
||||
name);
|
||||
format("\n");
|
||||
}
|
||||
format("} // internal\n");
|
||||
format("} // struct_pb\n");
|
||||
}
|
||||
void FileGenerator::generate_message_struct_pb_func_source(
|
||||
google::protobuf::io::Printer *p) {
|
||||
std::vector<const Descriptor *> msgs = flatten_messages_in_file(file_);
|
||||
Formatter format(p);
|
||||
format("namespace struct_pb {\n");
|
||||
format("namespace internal {\n");
|
||||
for (auto msg : msgs) {
|
||||
auto name = qualified_class_name(msg, options_);
|
||||
MessageGenerator g(msg, options_);
|
||||
format("// $1$\n", name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"std::size_t get_needed_size<$1$>(const $1$& t, const "
|
||||
"::struct_pb::UnknownFields& unknown_fields) {\n",
|
||||
name);
|
||||
format.indent();
|
||||
g.generate_get_needed_size(p);
|
||||
format.outdent();
|
||||
format(
|
||||
"} // std::size_t get_needed_size<$1$>(const $1$& t, const "
|
||||
"::struct_pb::UnknownFields& unknown_fields)\n",
|
||||
name);
|
||||
|
||||
format(
|
||||
"template<>\n"
|
||||
"void serialize_to<$1$>(char* data, std::size_t size, const $1$& t, "
|
||||
"const ::struct_pb::UnknownFields& unknown_fields) {\n",
|
||||
name);
|
||||
format.indent();
|
||||
g.generate_serialize_to(p);
|
||||
format.outdent();
|
||||
format(
|
||||
"} // void serialize_to<$1$>(char* data, std::size_t size, const $1$& "
|
||||
"t, "
|
||||
"const ::struct_pb::UnknownFields& unknown_fields)\n",
|
||||
name);
|
||||
|
||||
format(
|
||||
"template<>\n"
|
||||
"bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size, "
|
||||
"::struct_pb::UnknownFields& unknown_fields) {\n",
|
||||
name);
|
||||
format.indent();
|
||||
g.generate_deserialize_to(p);
|
||||
format.outdent();
|
||||
format("return true;\n");
|
||||
format("} // bool deserialize_to<$1$>($1$&, const char*, std::size_t)\n",
|
||||
name);
|
||||
format("// end of $1$\n", name);
|
||||
format(
|
||||
"template<>\n"
|
||||
"bool deserialize_to<$1$>($1$& t, const char* data, std::size_t size) "
|
||||
"{\n",
|
||||
name);
|
||||
format.indent();
|
||||
format("::struct_pb::UnknownFields unknown_fields{};\n");
|
||||
format("return deserialize_to(t,data,size,unknown_fields);\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format("\n");
|
||||
}
|
||||
format("} // internal\n");
|
||||
format("} // struct_pb\n");
|
||||
}
|
||||
void FileGenerator::generate_ns_open(google::protobuf::io::Printer *p) {
|
||||
NamespaceOpener(p, options_.ns).open();
|
||||
}
|
||||
void FileGenerator::generate_ns_close(google::protobuf::io::Printer *p) {
|
||||
NamespaceOpener(p, options_.ns).close();
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
#pragma once
|
||||
#include "EnumGenerator.h"
|
||||
#include "GeneratorBase.h"
|
||||
#include "MessageGenerator.h"
|
||||
#include "Options.hpp"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
class FileGenerator : public GeneratorBase {
|
||||
public:
|
||||
FileGenerator(const google::protobuf::FileDescriptor *file, Options options);
|
||||
;
|
||||
void generate_header(google::protobuf::io::Printer *p);
|
||||
void generate_source(google::protobuf::io::Printer *p);
|
||||
|
||||
private:
|
||||
void generate_shared_header_code(google::protobuf::io::Printer *p);
|
||||
void generate_fwd_decls(google::protobuf::io::Printer *p);
|
||||
void generate_enum_definitions(google::protobuf::io::Printer *p);
|
||||
void generate_message_definitions(google::protobuf::io::Printer *p);
|
||||
void generate_message_struct_pb_func_definitions(
|
||||
google::protobuf::io::Printer *p);
|
||||
void generate_message_struct_pb_func_source(google::protobuf::io::Printer *p);
|
||||
void generate_dependency_includes(google::protobuf::io::Printer *p);
|
||||
void generate_ns_open(google::protobuf::io::Printer *p);
|
||||
void generate_ns_close(google::protobuf::io::Printer *p);
|
||||
|
||||
private:
|
||||
const google::protobuf::FileDescriptor *file_;
|
||||
std::vector<std::unique_ptr<MessageGenerator>> message_generators_;
|
||||
std::vector<std::unique_ptr<EnumGenerator>> enum_generators_;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,26 +0,0 @@
|
|||
#include "GeneratorBase.h"
|
||||
|
||||
#include <iostream>
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
// Convert lowerCamelCase and UpperCamelCase strings to lower_with_underscore.
|
||||
std::string convert(const std::string &camelCase) {
|
||||
std::string str(1, tolower(camelCase[0]));
|
||||
|
||||
// First place underscores between contiguous lower and upper case letters.
|
||||
// For example, `_LowerCamelCase` becomes `_Lower_Camel_Case`.
|
||||
for (auto it = camelCase.begin() + 1; it != camelCase.end(); ++it) {
|
||||
if (isupper(*it) && *(it - 1) != '_' && islower(*(it - 1))) {
|
||||
str += "_";
|
||||
}
|
||||
str += *it;
|
||||
}
|
||||
|
||||
// Then convert it to lower case.
|
||||
std::transform(str.begin(), str.end(), str.begin(), ::tolower);
|
||||
|
||||
return str;
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
#include "Options.hpp"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
using namespace google::protobuf;
|
||||
class GeneratorBase {
|
||||
public:
|
||||
GeneratorBase(Options options) : options_(options) {}
|
||||
|
||||
protected:
|
||||
Options options_;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,298 +0,0 @@
|
|||
#include "MapFieldGenerator.h"
|
||||
|
||||
#include "EnumFieldGenerator.h"
|
||||
#include "MessageFieldGenerator.h"
|
||||
#include "PrimitiveFieldGenerator.h"
|
||||
#include "StringFieldGenerator.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
MapFieldGenerator::MapFieldGenerator(const FieldDescriptor *field,
|
||||
const Options &options)
|
||||
: FieldGenerator(field, options) {}
|
||||
|
||||
static std::string get_type_name_help(FieldDescriptor::Type type) {
|
||||
switch (type) {
|
||||
case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
|
||||
return "double";
|
||||
case google::protobuf::FieldDescriptor::TYPE_FLOAT:
|
||||
return "float";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT64:
|
||||
return "int64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED64:
|
||||
return "uint64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED32:
|
||||
return "uint32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT32:
|
||||
return "int32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_BOOL:
|
||||
return "bool";
|
||||
case google::protobuf::FieldDescriptor::TYPE_STRING:
|
||||
case google::protobuf::FieldDescriptor::TYPE_BYTES:
|
||||
return "std::string";
|
||||
case google::protobuf::FieldDescriptor::TYPE_GROUP:
|
||||
// workaround for group
|
||||
return "std::string";
|
||||
default: {
|
||||
return "not support now";
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string MapFieldGenerator::cpp_type_name() const {
|
||||
return "std::map<" + get_key_type_name() + ", " + get_value_type_name() + ">";
|
||||
}
|
||||
std::string MapFieldGenerator::get_value_type_name() const {
|
||||
return get_kv_type_name_helper(d_->message_type()->field(1));
|
||||
}
|
||||
std::string MapFieldGenerator::get_key_type_name() const {
|
||||
return get_kv_type_name_helper(d_->message_type()->field(0));
|
||||
}
|
||||
std::string MapFieldGenerator::get_kv_type_name_helper(
|
||||
const FieldDescriptor *f) const {
|
||||
if (f->type() == FieldDescriptor::TYPE_MESSAGE) {
|
||||
return qualified_class_name(f->message_type(), options_);
|
||||
}
|
||||
else if (f->type() == FieldDescriptor::TYPE_ENUM) {
|
||||
return qualified_enum_name(f->enum_type(), options_);
|
||||
}
|
||||
else {
|
||||
return get_type_name_help(f->type());
|
||||
}
|
||||
}
|
||||
void MapFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
generate_calculate_size_only(p, value);
|
||||
}
|
||||
void MapFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("for(const auto& e: $1$) {\n", value);
|
||||
format.indent();
|
||||
format("std::size_t map_entry_sz = 0;\n");
|
||||
auto key_f = d_->message_type()->field(0);
|
||||
auto value_f = d_->message_type()->field(1);
|
||||
generate_calculate_kv_size(p, key_f, "e.first");
|
||||
generate_calculate_kv_size(p, value_f, "e.second");
|
||||
format("total += $1$ + calculate_varint_size(map_entry_sz) + map_entry_sz;",
|
||||
calculate_tag_size(d_));
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void MapFieldGenerator::generate_calculate_kv_size(
|
||||
google::protobuf::io::Printer *p, const FieldDescriptor *f,
|
||||
const std::string &value) const {
|
||||
Formatter format(p);
|
||||
switch (f->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print({{"value", value}, {"tag_sz", calculate_tag_size(f)}}, R"(
|
||||
std::size_t sz = get_needed_size($value$);
|
||||
map_entry_sz += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
format(
|
||||
"map_entry_sz += $1$ + calculate_varint_size($2$.size()) + "
|
||||
"$2$.size();\n",
|
||||
calculate_tag_size(f), value);
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
p->Print({{"tag_sz", calculate_tag_size(f)}},
|
||||
R"(
|
||||
map_entry_sz += $tag_sz$ + )");
|
||||
EnumFieldGenerator(f, options_).generate_calculate_size_only(p, value);
|
||||
format(";\n");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
format("map_entry_sz += $1$ + ", calculate_tag_size(f));
|
||||
PrimitiveFieldGenerator(f, options_)
|
||||
.generate_calculate_size_only(p, value);
|
||||
format(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
void MapFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
void MapFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
auto key_f = d_->message_type()->field(0);
|
||||
auto value_f = d_->message_type()->field(1);
|
||||
std::unique_ptr<FieldGenerator> kg;
|
||||
kg.reset(FieldGeneratorMap::MakeGenerator(key_f, options_));
|
||||
std::unique_ptr<FieldGenerator> vg;
|
||||
kg.reset(FieldGeneratorMap::MakeGenerator(value_f, options_));
|
||||
Formatter format(p);
|
||||
format("for(const auto& e: $1$) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_));
|
||||
format("std::size_t map_entry_sz = 0;\n");
|
||||
format("{\n");
|
||||
format.indent();
|
||||
generate_calculate_kv_size(p, key_f, "e.first");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format("{\n");
|
||||
format.indent();
|
||||
generate_calculate_kv_size(p, value_f, "e.second");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
|
||||
format("serialize_varint(data, pos, size, map_entry_sz);\n");
|
||||
format("{\n");
|
||||
format.indent();
|
||||
generate_serialize_kv_only(p, key_f, "e.first");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format("{\n");
|
||||
format.indent();
|
||||
generate_serialize_kv_only(p, value_f, "e.second");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void MapFieldGenerator::generate_serialize_kv_only(
|
||||
google::protobuf::io::Printer *p, const FieldDescriptor *f,
|
||||
const std::string &value) const {
|
||||
switch (f->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print({{"value", value}, {"tag", calculate_tag_str(f)}}, R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
std::size_t sz = get_needed_size($value$);
|
||||
serialize_varint(data, pos, size, sz);
|
||||
serialize_to(data + pos, sz, $value$);
|
||||
pos += sz;
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
StringFieldGenerator(f, options_).generate_serialization_only(p, value);
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
EnumFieldGenerator(f, options_).generate_serialization_only(p, value);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
p->Print({{"tag", calculate_tag_str(f)}},
|
||||
R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
)");
|
||||
PrimitiveFieldGenerator(f, options_)
|
||||
.generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void MapFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"tag", calculate_tag_str(d_)}},
|
||||
R"(
|
||||
case $tag$: {
|
||||
uint64_t sz = 0;
|
||||
ok = deserialize_varint(data, pos, size, sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
std::size_t cur_max_size = pos + sz;
|
||||
)");
|
||||
generate_deserialization_only(p, value);
|
||||
p->Print(R"(
|
||||
break;
|
||||
}
|
||||
)");
|
||||
}
|
||||
void MapFieldGenerator::generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
auto key_f = d_->message_type()->field(0);
|
||||
auto value_f = d_->message_type()->field(1);
|
||||
Formatter format(p);
|
||||
format("$1$ key_tmp_val{};\n", get_key_type_name());
|
||||
format("$1$ value_tmp_val{};\n", get_value_type_name());
|
||||
p->Print(
|
||||
{
|
||||
{"key_tag", calculate_tag_str(key_f)},
|
||||
},
|
||||
R"(
|
||||
while (pos < cur_max_size) {
|
||||
ok = read_tag(data, pos, size, tag);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
switch(tag) {
|
||||
case $key_tag$: {
|
||||
)");
|
||||
generate_deserialize_kv_only(p, key_f, "key_tmp_val", "cur_max_size");
|
||||
p->Print(
|
||||
{
|
||||
{"value_tag", calculate_tag_str(value_f)},
|
||||
},
|
||||
R"(
|
||||
break;
|
||||
}
|
||||
case $value_tag$: {
|
||||
)");
|
||||
generate_deserialize_kv_only(p, value_f, "value_tmp_val", "cur_max_size");
|
||||
p->Print({{"value", value}}, R"(
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
$value$[key_tmp_val] = std::move(value_tmp_val);
|
||||
)");
|
||||
}
|
||||
void MapFieldGenerator::generate_deserialize_kv_only(
|
||||
google::protobuf::io::Printer *p, const FieldDescriptor *f,
|
||||
const std::string &value, const std::string &max_size) const {
|
||||
switch (f->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print({{"value", value},
|
||||
{"tag", calculate_tag_str(f)},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
uint64_t msg_sz = 0;
|
||||
ok = deserialize_varint(data, pos, $max_size$, msg_sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
ok = deserialize_to($value$, data + pos, msg_sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
pos += msg_sz;
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
StringFieldGenerator(f, options_)
|
||||
.generate_deserialization_only(p, value, "str_sz", max_size);
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
EnumFieldGenerator(f, options_)
|
||||
.generate_deserialization_only(p, value, max_size);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
PrimitiveFieldGenerator(f, options_)
|
||||
.generate_deserialization_only(p, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,44 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class MapFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
MapFieldGenerator(const FieldDescriptor *field, const Options &options);
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
void generate_deserialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
|
||||
private:
|
||||
void generate_calculate_kv_size(google::protobuf::io::Printer *p,
|
||||
const FieldDescriptor *f,
|
||||
const std::string &value) const;
|
||||
void generate_serialize_kv_only(google::protobuf::io::Printer *p,
|
||||
const FieldDescriptor *f,
|
||||
const std::string &value) const;
|
||||
void generate_deserialize_kv_only(google::protobuf::io::Printer *p,
|
||||
const FieldDescriptor *f,
|
||||
const std::string &value,
|
||||
const std::string &max_size) const;
|
||||
|
||||
private:
|
||||
std::string get_key_type_name() const;
|
||||
std::string get_value_type_name() const;
|
||||
std::string get_kv_type_name_helper(const FieldDescriptor *f) const;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,149 +0,0 @@
|
|||
#include "MessageFieldGenerator.h"
|
||||
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
MessageFieldGenerator::MessageFieldGenerator(const FieldDescriptor *field,
|
||||
const Options &options)
|
||||
: FieldGenerator(field, options) {}
|
||||
void MessageFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
if (can_ignore_default_value) {
|
||||
p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"(
|
||||
if ($value$) {
|
||||
auto sz = get_needed_size(*$value$);
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"(
|
||||
auto sz = get_needed_size(*$value$);
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
)");
|
||||
}
|
||||
}
|
||||
void MessageFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
p->Print({{"value", value}, {"tag", calculate_tag_str(d_)}}, R"(
|
||||
if ($value$) {
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
auto sz = get_needed_size(*$value$);
|
||||
serialize_varint(data, pos, size, sz);
|
||||
serialize_to(data + pos, sz, *$value$);
|
||||
pos += sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
void MessageFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"value", value},
|
||||
{"tag", calculate_tag_str(d_)},
|
||||
{"classname", qualified_class_name(d_->message_type(), options_)}},
|
||||
R"(case $tag$: {
|
||||
if (!$value$) {
|
||||
$value$ = std::make_unique<$classname$>();
|
||||
}
|
||||
uint64_t sz = 0;
|
||||
ok = deserialize_varint(data, pos, size, sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
ok = deserialize_to(*$value$, data + pos, sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
pos += sz;
|
||||
break;
|
||||
}
|
||||
)");
|
||||
}
|
||||
std::string MessageFieldGenerator::cpp_type_name() const {
|
||||
return "std::unique_ptr<" +
|
||||
qualified_class_name(d_->message_type(), options_) + ">";
|
||||
}
|
||||
|
||||
RepeatedMessageFieldGenerator::RepeatedMessageFieldGenerator(
|
||||
const FieldDescriptor *field, const Options &options)
|
||||
: FieldGenerator(field, options) {}
|
||||
void RepeatedMessageFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (can_ignore_default_value) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_calculate_size_only(p, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
generate_calculate_size_only(p, value);
|
||||
}
|
||||
}
|
||||
void RepeatedMessageFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (can_ignore_default_value) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_serialization_only(p, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
void RepeatedMessageFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"tag", std::to_string(calculate_tag(d_))},
|
||||
{"value", value},
|
||||
{"classname", qualified_class_name(d_->message_type(), options_)}},
|
||||
R"(case $tag$: {
|
||||
uint64_t sz = 0;
|
||||
ok = deserialize_varint(data, pos, size, sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
$value$.emplace_back();
|
||||
ok = deserialize_to($value$.back(), data + pos, sz);
|
||||
if (!ok) {
|
||||
$value$.pop_back();
|
||||
return false;
|
||||
}
|
||||
pos += sz;
|
||||
break;
|
||||
}
|
||||
)");
|
||||
}
|
||||
std::string RepeatedMessageFieldGenerator::cpp_type_name() const {
|
||||
return "std::vector<" + qualified_class_name(d_->message_type(), options_) +
|
||||
">";
|
||||
}
|
||||
void RepeatedMessageFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"tag_sz", calculate_tag_size(d_)}, {"value", value}}, R"(
|
||||
for(const auto& e: $value$) {
|
||||
std::size_t sz = get_needed_size(e);
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
void RepeatedMessageFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
p->Print({{"tag", std::to_string(calculate_tag(d_))}, {"value", value}}, R"(
|
||||
for(const auto& e: $value$) {
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
std::size_t sz = get_needed_size(e);
|
||||
serialize_varint(data, pos, size, sz);
|
||||
serialize_to(data+pos, sz, e);
|
||||
pos += sz;
|
||||
}
|
||||
)");
|
||||
}
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,38 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class MessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
MessageFieldGenerator(const FieldDescriptor *field, const Options &options);
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
std::string cpp_type_name() const override;
|
||||
};
|
||||
class RepeatedMessageFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedMessageFieldGenerator(const FieldDescriptor *field,
|
||||
const Options &options);
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
std::string cpp_type_name() const override;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,209 +0,0 @@
|
|||
#include "MessageGenerator.h"
|
||||
|
||||
#include "EnumGenerator.h"
|
||||
#include "FieldGenerator.h"
|
||||
#include "helpers.hpp"
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::internal;
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
std::unordered_map<std::string_view, std::string> ClassVars(
|
||||
const Descriptor *descriptor, Options options) {
|
||||
std::unordered_map<std::string_view, std::string> vars{};
|
||||
vars.emplace("classname", resolve_keyword(descriptor->name()));
|
||||
vars.emplace("classtype", qualified_class_name(descriptor, options));
|
||||
return vars;
|
||||
}
|
||||
// copy from cpp compiler
|
||||
static std::string UnderscoresToCamelCase(const std::string &input,
|
||||
bool cap_next_letter) {
|
||||
std::string result;
|
||||
// Note: I distrust ctype.h due to locales.
|
||||
for (int i = 0; i < input.size(); i++) {
|
||||
if ('a' <= input[i] && input[i] <= 'z') {
|
||||
if (cap_next_letter) {
|
||||
result += input[i] + ('A' - 'a');
|
||||
}
|
||||
else {
|
||||
result += input[i];
|
||||
}
|
||||
cap_next_letter = false;
|
||||
}
|
||||
else if ('A' <= input[i] && input[i] <= 'Z') {
|
||||
// Capital letters are left as-is.
|
||||
result += input[i];
|
||||
cap_next_letter = false;
|
||||
}
|
||||
else if ('0' <= input[i] && input[i] <= '9') {
|
||||
result += input[i];
|
||||
cap_next_letter = true;
|
||||
}
|
||||
else {
|
||||
cap_next_letter = true;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void MessageGenerator::generate_struct_definition(
|
||||
google::protobuf::io::Printer *p) {
|
||||
// auto v = p->WithVars(ClassVars(d_, options_));
|
||||
Formatter format(p);
|
||||
format("struct $1$ {\n", resolve_keyword(d_->name()));
|
||||
format.indent();
|
||||
for (int i = 0; i < d_->enum_type_count(); ++i) {
|
||||
auto e = d_->enum_type(i);
|
||||
EnumGenerator(e, options_).generate_definition(p);
|
||||
}
|
||||
for (int i = 0; i < d_->oneof_decl_count(); ++i) {
|
||||
auto oneof = d_->oneof_decl(i);
|
||||
std::string enum_name = UnderscoresToCamelCase(oneof->name(), true);
|
||||
format("enum class $1$Case {\n", enum_name);
|
||||
format.indent();
|
||||
format("none = 0,\n");
|
||||
for (int j = 0; j < oneof->field_count(); ++j) {
|
||||
auto f = oneof->field(j);
|
||||
format("$1$ = $2$,\n", resolve_keyword(f->name()), f->number());
|
||||
}
|
||||
format.outdent();
|
||||
format("};\n");
|
||||
format("$1$Case $2$_case() const {\n", enum_name, oneof->name());
|
||||
format.indent();
|
||||
format("switch ($1$.index()) {\n", resolve_keyword(oneof->name()));
|
||||
format.indent();
|
||||
for (int j = 0; j < oneof->field_count(); ++j) {
|
||||
format("case $1$:\n", j + 1);
|
||||
format.indent();
|
||||
format("return $1$Case::$2$;\n", enum_name,
|
||||
resolve_keyword(oneof->field(j)->name()));
|
||||
format.outdent();
|
||||
}
|
||||
format("default:\n");
|
||||
format.indent();
|
||||
format("return $1$Case::none;\n", enum_name);
|
||||
format.outdent();
|
||||
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format("\n");
|
||||
}
|
||||
for (int i = 0; i < d_->nested_type_count(); ++i) {
|
||||
auto t = d_->nested_type(i);
|
||||
auto name = t->name();
|
||||
if (is_map_entry(t)) {
|
||||
continue;
|
||||
}
|
||||
MessageGenerator(t, options_).generate_struct_definition(p);
|
||||
}
|
||||
std::set<const OneofDescriptor *> oneof_set;
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
auto oneof = f->containing_oneof();
|
||||
if (oneof) {
|
||||
if (oneof_set.find(oneof) == oneof_set.end()) {
|
||||
OneofGenerator(oneof, options_).generate_definition(p);
|
||||
oneof_set.insert(oneof);
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else {
|
||||
fg_map_.get(f).generate_definition(p);
|
||||
}
|
||||
}
|
||||
if (options_.generate_eq_op) {
|
||||
format("bool operator==(const $1$&) const = default;\n", class_name(d_));
|
||||
}
|
||||
// format("std::size_t get_needed_size() const;\n");
|
||||
// format("std::string SerializeAsString() const;\n");
|
||||
// format("bool ParseFromArray(const char* data, std::size_t size);\n");
|
||||
format.outdent();
|
||||
format("};\n");
|
||||
}
|
||||
void MessageGenerator::generate_source(google::protobuf::io::Printer *p) {
|
||||
generate_get_needed_size(p);
|
||||
Formatter format(p);
|
||||
format("std::string $1$::SerializeAsString() const {\n", d_->name());
|
||||
format.indent();
|
||||
format("std::string buffer;\n");
|
||||
format("// calculate buffer size\n");
|
||||
format("std::size_t total = get_needed_size();\n");
|
||||
format("std::size_t pos = 0;\n");
|
||||
format("buffer.resize(total);\n");
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
// FieldGenerator(f, options_).generate_calculate_size(p);
|
||||
}
|
||||
format("return buffer;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void MessageGenerator::generate_get_needed_size(
|
||||
google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
format("std::size_t total = unknown_fields.total_size();\n");
|
||||
std::set<const OneofDescriptor *> oneof_set;
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
fg_map_.get(f).generate_calculate_size(p, true);
|
||||
}
|
||||
format("return total;\n");
|
||||
}
|
||||
void MessageGenerator::generate_serialize_to(google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
format("std::size_t pos = 0;\n");
|
||||
std::vector<const FieldDescriptor *> fs;
|
||||
fs.reserve(d_->field_count());
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
fs.push_back(d_->field(i));
|
||||
}
|
||||
std::sort(fs.begin(), fs.end(),
|
||||
[](const FieldDescriptor *lhs, const FieldDescriptor *rhs) {
|
||||
return lhs->number() < rhs->number();
|
||||
});
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = fs[i];
|
||||
format("{\n");
|
||||
format.indent();
|
||||
fg_map_.get(f).generate_serialization(p, true);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
format("unknown_fields.serialize_to(data, pos, size);\n");
|
||||
}
|
||||
void MessageGenerator::generate_deserialize_to(
|
||||
google::protobuf::io::Printer *p) {
|
||||
Formatter format(p);
|
||||
format("std::size_t pos = 0;\n");
|
||||
format("bool ok = false;\n");
|
||||
format("while (pos < size) {\n");
|
||||
format.indent();
|
||||
p->Print(R"(uint64_t tag = 0;
|
||||
ok = read_tag(data, pos, size, tag);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
switch(tag) {
|
||||
)");
|
||||
format.indent();
|
||||
for (int i = 0; i < d_->field_count(); ++i) {
|
||||
auto f = d_->field(i);
|
||||
fg_map_.get(f).generate_deserialization(p);
|
||||
}
|
||||
format("default: {\n");
|
||||
format.indent();
|
||||
format("ok = deserialize_unknown(data, pos, size, tag, unknown_fields);\n");
|
||||
format("return ok;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,33 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
#include "GeneratorBase.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
class FileGenerator;
|
||||
class MessageGenerator : public GeneratorBase {
|
||||
public:
|
||||
MessageGenerator(const google::protobuf::Descriptor *d, Options options)
|
||||
: GeneratorBase(options), d_(d), fg_map_(d, options) {}
|
||||
|
||||
void generate(google::protobuf::io::Printer *p);
|
||||
void generate_struct_definition(google::protobuf::io::Printer *p);
|
||||
void generate_source(google::protobuf::io::Printer *p);
|
||||
|
||||
private:
|
||||
void generate_get_needed_size(google::protobuf::io::Printer *p);
|
||||
void generate_serialize_to(google::protobuf::io::Printer *p);
|
||||
void generate_deserialize_to(google::protobuf::io::Printer *p);
|
||||
|
||||
private:
|
||||
const google::protobuf::Descriptor *d_;
|
||||
std::vector<std::string> field_name_list;
|
||||
std::vector<std::size_t> unpack_index_list;
|
||||
std::vector<std::size_t> field_number_list;
|
||||
std::map<std::size_t, std::size_t> n2i_map;
|
||||
std::map<std::size_t, std::size_t> i2n_map;
|
||||
FieldGeneratorMap fg_map_;
|
||||
friend class FileGenerator;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,323 +0,0 @@
|
|||
#include "OneofFieldGenerator.h"
|
||||
|
||||
#include "EnumFieldGenerator.h"
|
||||
#include "PrimitiveFieldGenerator.h"
|
||||
#include "StringFieldGenerator.h"
|
||||
#include "helpers.hpp"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
void OneofFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
format("if ($1$.index() == $2$) {\n", value, index());
|
||||
generate_calculate_size_only(p, value);
|
||||
format("\n}\n");
|
||||
}
|
||||
std::string OneofFieldGenerator::index() const {
|
||||
auto oneof = d_->containing_oneof();
|
||||
assert(oneof);
|
||||
int index = 0;
|
||||
for (int i = 0; i < oneof->field_count(); ++i) {
|
||||
if (oneof->field(i) == d_) {
|
||||
index = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
assert(index > 0);
|
||||
return std::to_string(index);
|
||||
}
|
||||
void OneofFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
auto oneof_value = "std::get<" + index() + ">(" + value + ")";
|
||||
|
||||
switch (d_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print({{"tag_sz", calculate_tag_size(d_)},
|
||||
{"index", index()},
|
||||
{"oneof_value", oneof_value},
|
||||
{"value", value}},
|
||||
R"(
|
||||
uint64_t sz = 0;
|
||||
if ($oneof_value$) {
|
||||
sz = get_needed_size(*$oneof_value$);
|
||||
}
|
||||
total += $tag_sz$ + calculate_varint_size(sz) + sz;
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
p->Print(
|
||||
{
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
},
|
||||
R"(
|
||||
total += $tag_sz$ + calculate_varint_size()");
|
||||
StringFieldGenerator(d_, options_)
|
||||
.generate_calculate_size_only(p, oneof_value);
|
||||
p->Print(") + ");
|
||||
|
||||
StringFieldGenerator(d_, options_)
|
||||
.generate_calculate_size_only(p, oneof_value);
|
||||
p->Print(";\n");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
EnumFieldGenerator(d_, options_)
|
||||
.generate_calculate_size_only(p, oneof_value);
|
||||
format(";\n");
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
PrimitiveFieldGenerator(d_, options_)
|
||||
.generate_calculate_size_only(p, oneof_value);
|
||||
format(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
void OneofFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
format("if ($1$.index() == $2$) {\n", value, index());
|
||||
generate_serialization_only(p, value);
|
||||
format("\n}\n");
|
||||
}
|
||||
void OneofFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
auto oneof_value = "std::get<" + index() + ">(" + value + ")";
|
||||
|
||||
switch (d_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print({{"value", value},
|
||||
{"tag", std::to_string(calculate_tag(d_))},
|
||||
{"index", index()},
|
||||
{"oneof_value", oneof_value}
|
||||
|
||||
},
|
||||
R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
if ($oneof_value$) {
|
||||
std::size_t sz = get_needed_size(*$oneof_value$);
|
||||
serialize_varint(data, pos, size, sz);
|
||||
serialize_to(data + pos, sz, *$oneof_value$);
|
||||
pos += sz;
|
||||
}
|
||||
else {
|
||||
serialize_varint(data, pos, size, 0);
|
||||
}
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
StringFieldGenerator(d_, options_)
|
||||
.generate_serialization_only(p, oneof_value);
|
||||
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
EnumFieldGenerator(d_, options_)
|
||||
.generate_serialization_only(p, oneof_value);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
p->Print({{"tag", calculate_tag_str(d_)}},
|
||||
R"(
|
||||
serialize_varint(data, pos, size, $tag$);
|
||||
)");
|
||||
PrimitiveFieldGenerator(d_, options_)
|
||||
.generate_serialization_only(p, oneof_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void OneofFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("case $1$: {\n", calculate_tag_str(d_));
|
||||
generate_deserialization_only(p, value);
|
||||
format("break;\n");
|
||||
format("}\n");
|
||||
}
|
||||
void OneofFieldGenerator::generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
const std::string &max_size) const {
|
||||
Formatter format(p);
|
||||
std::string oneof_value = "std::get<" + index() + ">(" + value + ")";
|
||||
|
||||
switch (d_->cpp_type()) {
|
||||
case FieldDescriptor::CPPTYPE_MESSAGE: {
|
||||
p->Print(
|
||||
{{"value", value},
|
||||
{"type_name", qualified_class_name(d_->message_type(), options_)},
|
||||
{"tag", std::to_string(calculate_tag(d_))},
|
||||
{"max_size", max_size},
|
||||
{"oneof_value", oneof_value},
|
||||
{"index", index()}},
|
||||
|
||||
R"(
|
||||
if ($value$.index() != $index$) {
|
||||
$value$.emplace<$index$>(new $type_name$());
|
||||
}
|
||||
uint64_t msg_sz = 0;
|
||||
ok = deserialize_varint(data, pos, $max_size$, msg_sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
ok = deserialize_to(*$oneof_value$, data + pos, msg_sz);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
pos += msg_sz;
|
||||
)");
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_STRING: {
|
||||
format("if ($1$.index() != $2$) {\n", value, index());
|
||||
format.indent();
|
||||
format("$1$.emplace<$2$>();\n", value, index());
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
StringFieldGenerator(d_, options_)
|
||||
.generate_deserialization_only(p, oneof_value, "str_sz", max_size);
|
||||
break;
|
||||
}
|
||||
case FieldDescriptor::CPPTYPE_ENUM: {
|
||||
format("if ($1$.index() != $2$) {\n", value, index());
|
||||
format.indent();
|
||||
format("$1$.emplace<$2$>();\n", value, index());
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
EnumFieldGenerator(d_, options_)
|
||||
.generate_deserialization_only(p, oneof_value, max_size);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
format("if ($1$.index() != $2$) {\n", value, index());
|
||||
format.indent();
|
||||
format("$1$.emplace<$2$>();\n", value, index());
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
PrimitiveFieldGenerator(d_, options_)
|
||||
.generate_deserialization_only(p, oneof_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string OneofFieldGenerator::cpp_type_name() const {
|
||||
return "std::variant";
|
||||
}
|
||||
std::string OneofFieldGenerator::pb_type_name() const {
|
||||
return d_->type_name();
|
||||
}
|
||||
OneofFieldGenerator::OneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options)
|
||||
: FieldGenerator(descriptor, options) {}
|
||||
|
||||
MessageOneofFieldGenerator::MessageOneofFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: OneofFieldGenerator(descriptor, options) {}
|
||||
|
||||
void MessageOneofFieldGenerator::generate_setter_and_getter(
|
||||
google::protobuf::io::Printer *p) {
|
||||
auto oneof = d_->containing_oneof();
|
||||
assert(oneof);
|
||||
std::string type_name = get_type_name();
|
||||
type_name = qualified_class_name(d_->message_type(), options_);
|
||||
p->Print({{"name", resolve_keyword(d_->name())},
|
||||
{"type_name", type_name},
|
||||
{"field_name", resolve_keyword(oneof->name())},
|
||||
{"index", index()}},
|
||||
R"(
|
||||
bool has_$name$() const {
|
||||
return $field_name$.index() == $index$;
|
||||
}
|
||||
void set_allocated_$name$($type_name$* p) {
|
||||
assert(p);
|
||||
$field_name$.emplace<$index$>(p);
|
||||
}
|
||||
const std::unique_ptr<$type_name$>& $name$() const {
|
||||
assert($field_name$.index() == $index$);
|
||||
return std::get<$index$>($field_name$);
|
||||
}
|
||||
)");
|
||||
}
|
||||
PrimitiveOneofFieldGenerator::PrimitiveOneofFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: OneofFieldGenerator(descriptor, options) {}
|
||||
void PrimitiveOneofFieldGenerator::generate_setter_and_getter(
|
||||
google::protobuf::io::Printer *p) {
|
||||
auto oneof = d_->containing_oneof();
|
||||
assert(oneof);
|
||||
std::string type_name = get_type_name();
|
||||
p->Print({{"name", resolve_keyword(d_->name())},
|
||||
{"type_name", type_name},
|
||||
{"field_name", resolve_keyword(oneof->name())},
|
||||
{"index", index()}},
|
||||
R"(
|
||||
bool has_$name$() const {
|
||||
return $field_name$.index() == $index$;
|
||||
}
|
||||
void set_$name$($type_name$ $name$) {
|
||||
$field_name$.emplace<$index$>($name$);
|
||||
}
|
||||
$type_name$ $name$() const {
|
||||
assert($field_name$.index() == $index$);
|
||||
return std::get<$index$>($field_name$);
|
||||
}
|
||||
)");
|
||||
}
|
||||
StringOneofFieldGenerator::StringOneofFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: OneofFieldGenerator(descriptor, options) {}
|
||||
void StringOneofFieldGenerator::generate_setter_and_getter(
|
||||
google::protobuf::io::Printer *p) {
|
||||
auto oneof = d_->containing_oneof();
|
||||
assert(oneof);
|
||||
std::string type_name = get_type_name();
|
||||
p->Print({{"name", resolve_keyword(d_->name())},
|
||||
{"type_name", type_name},
|
||||
{"field_name", resolve_keyword(oneof->name())},
|
||||
{"index", index()}},
|
||||
R"(
|
||||
bool has_$name$() const {
|
||||
return $field_name$.index() == $index$;
|
||||
}
|
||||
void set_$name$($type_name$ $name$) {
|
||||
$field_name$.emplace<$index$>(std::move($name$));
|
||||
}
|
||||
const $type_name$& $name$() const {
|
||||
assert($field_name$.index() == $index$);
|
||||
return std::get<$index$>($field_name$);
|
||||
}
|
||||
)");
|
||||
}
|
||||
EnumOneofFieldGenerator::EnumOneofFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: OneofFieldGenerator(descriptor, options) {}
|
||||
void EnumOneofFieldGenerator::generate_setter_and_getter(
|
||||
google::protobuf::io::Printer *p) {
|
||||
auto oneof = d_->containing_oneof();
|
||||
assert(oneof);
|
||||
std::string type_name = get_type_name();
|
||||
type_name = qualified_enum_name(d_->enum_type(), options_);
|
||||
p->Print({{"name", resolve_keyword(d_->name())},
|
||||
{"type_name", type_name},
|
||||
{"field_name", resolve_keyword(oneof->name())},
|
||||
{"index", index()}},
|
||||
R"(
|
||||
bool has_$name$() const {
|
||||
return $field_name$.index() == $index$;
|
||||
}
|
||||
void set_allocated_$name$($type_name$ p) {
|
||||
$field_name$.emplace<$index$>(p);
|
||||
}
|
||||
$type_name$ $name$() const {
|
||||
assert($field_name$.index() == $index$);
|
||||
return std::get<$index$>($field_name$);
|
||||
}
|
||||
)");
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class OneofFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
OneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
|
||||
void generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
const std::string &max_size = "size") const;
|
||||
std::string cpp_type_name() const override;
|
||||
std::string pb_type_name() const override;
|
||||
virtual void generate_setter_and_getter(google::protobuf::io::Printer *p){};
|
||||
|
||||
protected:
|
||||
std::string index() const;
|
||||
};
|
||||
|
||||
class MessageOneofFieldGenerator : public OneofFieldGenerator {
|
||||
public:
|
||||
MessageOneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
void generate_setter_and_getter(google::protobuf::io::Printer *p) override;
|
||||
};
|
||||
|
||||
class StringOneofFieldGenerator : public OneofFieldGenerator {
|
||||
public:
|
||||
StringOneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
void generate_setter_and_getter(google::protobuf::io::Printer *p) override;
|
||||
};
|
||||
|
||||
class EnumOneofFieldGenerator : public OneofFieldGenerator {
|
||||
public:
|
||||
EnumOneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
void generate_setter_and_getter(google::protobuf::io::Printer *p) override;
|
||||
};
|
||||
|
||||
class PrimitiveOneofFieldGenerator : public OneofFieldGenerator {
|
||||
public:
|
||||
PrimitiveOneofFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
void generate_setter_and_getter(google::protobuf::io::Printer *p) override;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "google/protobuf/descriptor.h"
|
||||
struct Options {
|
||||
Options(const google::protobuf::FileDescriptor* f) : f(f) {}
|
||||
bool generate_eq_op = false;
|
||||
std::string ns;
|
||||
const google::protobuf::FileDescriptor* f;
|
||||
};
|
||||
|
|
@ -1,453 +0,0 @@
|
|||
#include "PrimitiveFieldGenerator.h"
|
||||
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
std::string get_type_name_help(FieldDescriptor::Type type) {
|
||||
switch (type) {
|
||||
case google::protobuf::FieldDescriptor::TYPE_DOUBLE:
|
||||
return "double";
|
||||
case google::protobuf::FieldDescriptor::TYPE_FLOAT:
|
||||
return "float";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT64:
|
||||
return "int64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT64:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED64:
|
||||
return "uint64_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_UINT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_FIXED32:
|
||||
return "uint32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_INT32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SFIXED32:
|
||||
case google::protobuf::FieldDescriptor::TYPE_SINT32:
|
||||
return "int32_t";
|
||||
case google::protobuf::FieldDescriptor::TYPE_BOOL:
|
||||
return "bool";
|
||||
default: {
|
||||
// can't reach, dead path
|
||||
return "not support";
|
||||
}
|
||||
}
|
||||
}
|
||||
PrimitiveFieldGenerator::PrimitiveFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: FieldGenerator(descriptor, options) {}
|
||||
void PrimitiveFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (is_optional()) {
|
||||
format("if ($1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
generate_calculate_size_only(p, value + ".value()");
|
||||
format(";\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
format("if ($1$ != 0) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
generate_calculate_size_only(p, value);
|
||||
format(";\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
format("total += $1$ + ", calculate_tag_size(d_));
|
||||
generate_calculate_size_only(p, value);
|
||||
format(";\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
void PrimitiveFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
if (is_varint(d_)) {
|
||||
if (is_sint(d_)) {
|
||||
format("calculate_varint_size(encode_zigzag($1$))", value);
|
||||
}
|
||||
else if (is_bool(d_)) {
|
||||
format("calculate_varint_size(static_cast<uint64_t>($1$))", value);
|
||||
}
|
||||
else {
|
||||
format("calculate_varint_size($1$)", value);
|
||||
}
|
||||
}
|
||||
else if (is_i64(d_)) {
|
||||
format("8");
|
||||
}
|
||||
else if (is_i32(d_)) {
|
||||
format("4");
|
||||
}
|
||||
}
|
||||
|
||||
std::string PrimitiveFieldGenerator::cpp_type_name() const {
|
||||
std::string type_name = get_type_name_help(d_->type());
|
||||
if (is_optional()) {
|
||||
type_name = "std::optional<" + type_name + ">";
|
||||
}
|
||||
return type_name;
|
||||
}
|
||||
void PrimitiveFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (is_optional()) {
|
||||
format("if ($1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_));
|
||||
generate_serialization_only(p, value + ".value()");
|
||||
format("\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
format("if ($1$ != 0) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n",
|
||||
calculate_tag_str(d_));
|
||||
generate_serialization_only(p, value);
|
||||
format("\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
format("serialize_varint(data, pos, size, $1$);\n",
|
||||
calculate_tag_str(d_));
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void PrimitiveFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
if (is_varint(d_)) {
|
||||
if (is_sint(d_)) {
|
||||
format("serialize_varint(data, pos, size, encode_zigzag($1$));", value);
|
||||
}
|
||||
else if (is_bool(d_)) {
|
||||
format("serialize_varint(data, pos, size, static_cast<uint64_t>($1$));",
|
||||
value);
|
||||
}
|
||||
else {
|
||||
if (d_->cpp_type() != FieldDescriptor::CPPTYPE_UINT64) {
|
||||
format("serialize_varint(data, pos, size, static_cast<uint64_t>($1$));",
|
||||
value);
|
||||
}
|
||||
else {
|
||||
format("serialize_varint(data, pos, size, $1$);", value);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
std::size_t sz = is_i64(d_) ? 8 : 4;
|
||||
p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"(
|
||||
std::memcpy(data + pos, &$value$, $sz$);
|
||||
pos += $sz$;
|
||||
)");
|
||||
}
|
||||
}
|
||||
void PrimitiveFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("case $1$: {\n", calculate_tag_str(d_));
|
||||
format.indent();
|
||||
generate_deserialization_only(p, value);
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void PrimitiveFieldGenerator::generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &max_size) const {
|
||||
if (is_varint(d_)) {
|
||||
p->Print({{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
uint64_t varint_tmp = 0;
|
||||
ok = deserialize_varint(data, pos, $max_size$, varint_tmp);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
)");
|
||||
if (is_sint(d_)) {
|
||||
if (is_sint32(d_)) {
|
||||
p->Print(
|
||||
{
|
||||
|
||||
{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
$output$ = static_cast<$type_name$>(decode_zigzag(uint32_t(varint_tmp)));
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print(
|
||||
{
|
||||
|
||||
{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
$output$ = static_cast<$type_name$>(decode_zigzag(varint_tmp));
|
||||
)");
|
||||
}
|
||||
}
|
||||
else if (is_bool(d_)) {
|
||||
p->Print(
|
||||
{
|
||||
|
||||
{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
$output$ = static_cast<$type_name$>(varint_tmp);
|
||||
)");
|
||||
}
|
||||
else {
|
||||
p->Print(
|
||||
{
|
||||
|
||||
{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size}},
|
||||
R"(
|
||||
$output$ = varint_tmp;
|
||||
)");
|
||||
}
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
auto sz = is_i64(d_) ? 8 : 4;
|
||||
p->Print(
|
||||
{
|
||||
|
||||
{"output", output},
|
||||
{"type_name", get_type_name_help(d_->type())},
|
||||
{"max_size", max_size},
|
||||
{"sz", std::to_string(sz)}},
|
||||
R"(
|
||||
if (pos + $sz$ > $max_size$) {
|
||||
return false;
|
||||
}
|
||||
$type_name$ fixed_tmp = 0;
|
||||
std::memcpy(&fixed_tmp, data + pos, $sz$);
|
||||
pos += $sz$;
|
||||
$output$ = fixed_tmp;
|
||||
)");
|
||||
}
|
||||
}
|
||||
RepeatedPrimitiveFieldGenerator::RepeatedPrimitiveFieldGenerator(
|
||||
const FieldDescriptor *descriptor, const Options &options)
|
||||
: FieldGenerator(descriptor, options) {}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
if (is_packed()) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_calculate_packed_size_only(p, value);
|
||||
format(
|
||||
"total += $1$ + calculate_varint_size(container_total) + "
|
||||
"container_total;\n",
|
||||
calculate_tag_size(d_));
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_calculate_unpacked_size_only(p, value);
|
||||
format("total += container_total;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
}
|
||||
bool RepeatedPrimitiveFieldGenerator::is_packed() const {
|
||||
return d_->is_packable() && d_->is_packed();
|
||||
}
|
||||
std::string RepeatedPrimitiveFieldGenerator::cpp_type_name() const {
|
||||
return "std::vector<" + get_type_name_help(d_->type()) + ">";
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_calculate_packed_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
if (is_varint(d_)) {
|
||||
p->Print({{"value", value}},
|
||||
R"(
|
||||
std::size_t container_total = 0;
|
||||
for(const auto& e: $value$) {
|
||||
container_total += )");
|
||||
g.generate_calculate_size_only(p, "e");
|
||||
format(";\n");
|
||||
format("}\n");
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
auto sz = is_i64(d_) ? 8 : 4;
|
||||
p->Print({{"sz", std::to_string(sz)}, {"value", value}}, R"(
|
||||
std::size_t container_total = $sz$ * $value$.size();
|
||||
)");
|
||||
}
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_calculate_unpacked_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
Formatter format(p);
|
||||
if (is_varint(d_)) {
|
||||
p->Print({{"value", value}, {"tag_sz", calculate_tag_size(d_, true)}},
|
||||
R"(
|
||||
std::size_t container_total = 0;
|
||||
for(const auto& e: $value$) {
|
||||
container_total += $tag_sz$;
|
||||
container_total += )");
|
||||
g.generate_calculate_size_only(p, "e");
|
||||
format(";\n");
|
||||
format("}\n");
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
auto sz = is_i64(d_) ? 8 : 4;
|
||||
p->Print({{"sz", std::to_string(sz)},
|
||||
{"value", value},
|
||||
{"tag_sz", calculate_tag_size(d_, true)}},
|
||||
R"(
|
||||
std::size_t container_total = ($tag_sz$ + $sz$) * $value$.size();
|
||||
)");
|
||||
}
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
Formatter format(p);
|
||||
if (is_packed()) {
|
||||
if (is_varint(d_)) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n",
|
||||
calculate_tag_str(d_));
|
||||
generate_calculate_packed_size_only(p, value);
|
||||
format("serialize_varint(data, pos, size, container_total);\n");
|
||||
format("for(const auto& v: $1$) {\n", value);
|
||||
format.indent();
|
||||
g.generate_serialization_only(p, "v");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n",
|
||||
calculate_tag_str(d_));
|
||||
generate_calculate_packed_size_only(p, value);
|
||||
format("serialize_varint(data, pos, size, container_total);\n");
|
||||
format("std::memcpy(data + pos, $1$.data(), container_total);\n", value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
}
|
||||
else {
|
||||
format("for(const auto& v: $1$) {\n", value);
|
||||
format.indent();
|
||||
format("serialize_varint(data, pos, size, $1$);\n",
|
||||
calculate_tag_str(d_, true));
|
||||
g.generate_serialization_only(p, "v");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("case $1$: {\n", unpacked_tag());
|
||||
format.indent();
|
||||
format("$1$ e{};\n", get_type_name_help(d_->type()));
|
||||
generate_deserialization_unpacked_only(p, "e");
|
||||
format("$1$.push_back(e);\n", value);
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
|
||||
format("case $1$: {\n", packed_tag());
|
||||
format.indent();
|
||||
format("uint64_t sz = 0;\n");
|
||||
format("ok = deserialize_varint(data, pos, size, sz);\n");
|
||||
format("if (!ok) {\n");
|
||||
format.indent();
|
||||
format("return false;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
format("std::size_t cur_max_size = pos + sz;\n");
|
||||
generate_deserialization_packed_only(p, value, "cur_max_size");
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_deserialization_packed_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
const std::string &max_size) const {
|
||||
if (is_varint(d_)) {
|
||||
Formatter format(p);
|
||||
format("while (pos < $1$) {\n", max_size);
|
||||
format.indent();
|
||||
format("$1$ e{};\n", get_type_name_help(d_->type()));
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
g.generate_deserialization_only(p, "e");
|
||||
format("$1$.push_back(e);\n", value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else if (is_i64(d_) || is_i32(d_)) {
|
||||
auto sz = is_i64(d_) ? 8 : 4;
|
||||
p->Print({{"value", value}, {"sz", std::to_string(sz)}}, R"(
|
||||
int count = sz / $sz$;
|
||||
if ($sz$ * count != sz) {
|
||||
return false;
|
||||
}
|
||||
if (pos + sz > size) {
|
||||
return false;
|
||||
}
|
||||
$value$.resize(count);
|
||||
std::memcpy($value$.data(), data + pos, sz);
|
||||
pos += sz;
|
||||
)");
|
||||
}
|
||||
}
|
||||
std::string RepeatedPrimitiveFieldGenerator::packed_tag() const {
|
||||
uint32_t number = d_->number();
|
||||
uint32_t wire_type = 2;
|
||||
auto tag = number << 3 | wire_type;
|
||||
return std::to_string(tag);
|
||||
}
|
||||
std::string RepeatedPrimitiveFieldGenerator::unpacked_tag() const {
|
||||
uint32_t number = d_->number();
|
||||
uint32_t wire_type = 0;
|
||||
if (is_varint(d_)) {
|
||||
wire_type = 0;
|
||||
}
|
||||
else if (is_i64(d_)) {
|
||||
wire_type = 1;
|
||||
}
|
||||
else if (is_i32(d_)) {
|
||||
wire_type = 5;
|
||||
}
|
||||
auto tag = number << 3 | wire_type;
|
||||
return std::to_string(tag);
|
||||
}
|
||||
void RepeatedPrimitiveFieldGenerator::generate_deserialization_unpacked_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output) const {
|
||||
PrimitiveFieldGenerator g(d_, options_);
|
||||
g.generate_deserialization_only(p, output);
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,59 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
using namespace google::protobuf;
|
||||
class PrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
PrimitiveFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
PrimitiveFieldGenerator(const PrimitiveFieldGenerator &) = delete;
|
||||
PrimitiveFieldGenerator &operator=(const PrimitiveFieldGenerator &) = delete;
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
void generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &max_size = "size") const;
|
||||
};
|
||||
class RepeatedPrimitiveFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedPrimitiveFieldGenerator(const FieldDescriptor *descriptor,
|
||||
const Options &options);
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value = {},
|
||||
bool can_ignore_default_value = true) const override;
|
||||
void generate_calculate_packed_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_calculate_unpacked_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
void generate_deserialization_packed_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
const std::string &max_size) const;
|
||||
void generate_deserialization_unpacked_only(google::protobuf::io::Printer *p,
|
||||
const std::string &output) const;
|
||||
|
||||
private:
|
||||
bool is_packed() const;
|
||||
std::string packed_tag() const;
|
||||
std::string unpacked_tag() const;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,185 +0,0 @@
|
|||
#include "StringFieldGenerator.h"
|
||||
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
StringFieldGenerator::StringFieldGenerator(const FieldDescriptor *field,
|
||||
const Options &options)
|
||||
: FieldGenerator(field, options) {}
|
||||
void StringFieldGenerator::generate_calculate_size_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("$1$.size()", value);
|
||||
}
|
||||
void StringFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
auto tag_sz = calculate_tag_size(d_);
|
||||
if (is_optional()) {
|
||||
format("if ($1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + calculate_varint_size($2$->size()) + $2$->size();\n",
|
||||
tag_sz, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n",
|
||||
tag_sz, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
format("total += $1$ + calculate_varint_size($2$.size()) + $2$.size();\n",
|
||||
tag_sz, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void StringFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (is_optional()) {
|
||||
format("if ($1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
generate_serialization_only(p, value + ".value()");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
if (can_ignore_default_value) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_serialization_only(p, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
void StringFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("serialize_varint(data, pos, size, $1$);\n", calculate_tag_str(d_));
|
||||
format("serialize_varint(data, pos, size, $1$.size());\n", value);
|
||||
format("std::memcpy(data + pos, $1$.data(), $1$.size());\n", value);
|
||||
format("pos += $1$.size();\n", value);
|
||||
}
|
||||
std::string StringFieldGenerator::cpp_type_name() const {
|
||||
if (d_->has_presence()) {
|
||||
return "std::optional<std::string>";
|
||||
}
|
||||
return "std::string";
|
||||
}
|
||||
void StringFieldGenerator::generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &sz, const std::string &max_size) const {
|
||||
p->Print({{"output", output}, {"sz", sz}, {"max_size", max_size}},
|
||||
R"(uint64_t $sz$ = 0;
|
||||
ok = deserialize_varint(data, pos, $max_size$, $sz$);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
$output$.resize($sz$);
|
||||
if (pos + $sz$ > $max_size$) {
|
||||
return false;
|
||||
}
|
||||
std::memcpy($output$.data(), data+pos, $sz$);
|
||||
pos += $sz$;
|
||||
)");
|
||||
}
|
||||
void StringFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("case $1$: {\n", calculate_tag_str(d_));
|
||||
format.indent();
|
||||
if (is_optional()) {
|
||||
format("if (!$1$.has_value()) {\n", value);
|
||||
format.indent();
|
||||
format("$1$ = std::string();\n", value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
generate_deserialization_only(p, value + ".value()");
|
||||
}
|
||||
else {
|
||||
generate_deserialization_only(p, value);
|
||||
}
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
RepeatedStringFieldGenerator::RepeatedStringFieldGenerator(
|
||||
const FieldDescriptor *field, const Options &options)
|
||||
: FieldGenerator(field, options) {}
|
||||
std::string RepeatedStringFieldGenerator::cpp_type_name() const {
|
||||
return "std::vector<std::string>";
|
||||
}
|
||||
void RepeatedStringFieldGenerator::generate_calculate_size(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
format("for (const auto& s: $1$) {\n", value);
|
||||
format.indent();
|
||||
format("total += $1$ + calculate_varint_size(s.size()) + s.size();\n",
|
||||
calculate_tag_size(d_));
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void RepeatedStringFieldGenerator::generate_calculate_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
const std::string &output) const {
|
||||
p->Print({{"value", value},
|
||||
{"tag_sz", calculate_tag_size(d_)},
|
||||
{"output", output}},
|
||||
R"(
|
||||
std::size_t $output$ = 0;
|
||||
for (const auto& s: $value$) {
|
||||
$output$ += $tag_sz$ + calculate_varint_size(s.size()) + s.size();
|
||||
}
|
||||
)");
|
||||
}
|
||||
void RepeatedStringFieldGenerator::generate_serialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value,
|
||||
bool can_ignore_default_value) const {
|
||||
Formatter format(p);
|
||||
if (can_ignore_default_value) {
|
||||
format("if (!$1$.empty()) {\n", value);
|
||||
format.indent();
|
||||
generate_serialization_only(p, value);
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
else {
|
||||
generate_serialization_only(p, value);
|
||||
}
|
||||
}
|
||||
void RepeatedStringFieldGenerator::generate_serialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
Formatter format(p);
|
||||
format("for(const auto& s: $1$) {\n", value);
|
||||
format.indent();
|
||||
StringFieldGenerator g(d_, options_);
|
||||
g.generate_serialization_only(p, "s");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
void RepeatedStringFieldGenerator::generate_deserialization(
|
||||
google::protobuf::io::Printer *p, const std::string &value) const {
|
||||
StringFieldGenerator g(d_, options_);
|
||||
Formatter format(p);
|
||||
format("case $1$: {\n", calculate_tag_str(d_));
|
||||
format.indent();
|
||||
format("std::string tmp_str;\n");
|
||||
g.generate_deserialization_only(p, "tmp_str");
|
||||
format("$1$.push_back(std::move(tmp_str));\n", value);
|
||||
format("break;\n");
|
||||
format.outdent();
|
||||
format("}\n");
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#pragma once
|
||||
#include "FieldGenerator.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class StringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
StringFieldGenerator(const FieldDescriptor *field, const Options &options);
|
||||
std::string cpp_type_name() const override;
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_size_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value = {}) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
void generate_deserialization_only(
|
||||
google::protobuf::io::Printer *p, const std::string &output,
|
||||
const std::string &sz = "sz", const std::string &max_size = "size") const;
|
||||
};
|
||||
class RepeatedStringFieldGenerator : public FieldGenerator {
|
||||
public:
|
||||
RepeatedStringFieldGenerator(const FieldDescriptor *field,
|
||||
const Options &options);
|
||||
void generate_calculate_size(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_calculate_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
const std::string &output) const;
|
||||
void generate_serialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value,
|
||||
bool can_ignore_default_value) const override;
|
||||
void generate_serialization_only(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const;
|
||||
void generate_deserialization(google::protobuf::io::Printer *p,
|
||||
const std::string &value) const override;
|
||||
std::string cpp_type_name() const override;
|
||||
};
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
#include "StructGenerator.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "FileGenerator.h"
|
||||
#include "Options.hpp"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "helpers.hpp"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
bool StructGenerator::Generate(
|
||||
const google::protobuf::FileDescriptor *file, const std::string ¶meter,
|
||||
google::protobuf::compiler::GeneratorContext *generator_context,
|
||||
std::string *error) const {
|
||||
std::vector<std::pair<std::string, std::string>> options;
|
||||
google::protobuf::compiler::ParseGeneratorParameter(parameter, &options);
|
||||
Options struct_pb_options(file);
|
||||
for (const auto &option : options) {
|
||||
const auto &key = option.first;
|
||||
const auto &value = option.second;
|
||||
if (key == "generate_eq_op") {
|
||||
struct_pb_options.generate_eq_op = true;
|
||||
}
|
||||
else if (key == "namespace") {
|
||||
struct_pb_options.ns = value;
|
||||
}
|
||||
else {
|
||||
*error = "Unknown generator option: " + key;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (struct_pb_options.ns.empty()) {
|
||||
struct_pb_options.ns = file->package();
|
||||
}
|
||||
auto basename = strip_proto(file->name());
|
||||
FileGenerator file_generator(file, struct_pb_options);
|
||||
// generate xxx.struct_pb.h
|
||||
{
|
||||
std::unique_ptr<io::ZeroCopyOutputStream> output(
|
||||
generator_context->Open(basename + ".struct_pb.h"));
|
||||
google::protobuf::io::Printer p(output.get(), '$');
|
||||
p.Print({{"parameter", parameter}}, R"(// protoc generate parameter
|
||||
// clang-format off
|
||||
// $parameter$
|
||||
// =========================
|
||||
#pragma once
|
||||
|
||||
)");
|
||||
file_generator.generate_header(&p);
|
||||
}
|
||||
// generate xxx.struct_pb.cc
|
||||
{
|
||||
std::unique_ptr<io::ZeroCopyOutputStream> output(
|
||||
generator_context->Open(basename + ".struct_pb.cc"));
|
||||
google::protobuf::io::Printer p(output.get(), '$');
|
||||
p.Print(
|
||||
{{"parameter", parameter}, {"header_file", basename + ".struct_pb.h"}},
|
||||
R"(// protoc generate parameter
|
||||
// clang-format off
|
||||
// $parameter$
|
||||
// =========================
|
||||
#include "$header_file$"
|
||||
#include "ylt/struct_pb/struct_pb_impl.hpp"
|
||||
)");
|
||||
Formatter format(&p);
|
||||
file_generator.generate_source(&p);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,15 +0,0 @@
|
|||
#pragma once
|
||||
#include <google/protobuf/compiler/code_generator.h>
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
|
||||
class StructGenerator : public google::protobuf::compiler::CodeGenerator {
|
||||
public:
|
||||
bool Generate(const google::protobuf::FileDescriptor *file,
|
||||
const std::string ¶meter,
|
||||
google::protobuf::compiler::GeneratorContext *generator_context,
|
||||
std::string *error) const override;
|
||||
};
|
||||
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
#include "helpers.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
|
||||
#include "google/protobuf/io/printer.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
// https://stackoverflow.com/questions/236129/how-do-i-iterate-over-the-words-of-a-string
|
||||
template <typename Out>
|
||||
void split(const std::string &s, char delim, Out result) {
|
||||
std::istringstream iss(s);
|
||||
std::string item;
|
||||
while (std::getline(iss, item, delim)) {
|
||||
*result++ = item;
|
||||
}
|
||||
}
|
||||
|
||||
static std::vector<std::string> split(const std::string &s, char delim) {
|
||||
std::vector<std::string> elems;
|
||||
split(s, delim, std::back_inserter(elems));
|
||||
return elems;
|
||||
}
|
||||
NamespaceOpener::NamespaceOpener(google::protobuf::io::Printer *p,
|
||||
const std::string &package)
|
||||
: p_(p) {
|
||||
ns_ = split(package, '.');
|
||||
}
|
||||
NamespaceOpener::~NamespaceOpener() {}
|
||||
void NamespaceOpener::open() const {
|
||||
for (const auto &ns : ns_) {
|
||||
p_->Print({{"ns", ns}}, R"(
|
||||
namespace $ns$ {
|
||||
)");
|
||||
}
|
||||
}
|
||||
void NamespaceOpener::close() const {
|
||||
for (int i = 0; i < ns_.size(); ++i) {
|
||||
auto ns = ns_[ns_.size() - i - 1];
|
||||
p_->Print({{"ns", ns}}, R"(
|
||||
} // namespace $ns$
|
||||
)");
|
||||
}
|
||||
}
|
||||
// from std::string_view ends_with
|
||||
bool string_ends_with(std::string_view s, std::string_view suffix) {
|
||||
return s.size() >= suffix.size() &&
|
||||
s.compare(s.size() - suffix.size(), std::string_view::npos, suffix) ==
|
||||
0;
|
||||
}
|
||||
std::string_view string_strip_suffix(const std::string_view s,
|
||||
const std::string_view suffix) {
|
||||
if (string_ends_with(s, suffix)) {
|
||||
return s.substr(0, s.size() - suffix.size());
|
||||
}
|
||||
return s;
|
||||
}
|
||||
std::string strip_proto(const std::string &filename) {
|
||||
if (string_ends_with(filename, ".protodevel")) {
|
||||
return std::string(string_strip_suffix(filename, ".protodevel"));
|
||||
}
|
||||
else {
|
||||
return std::string(string_strip_suffix(filename, ".proto"));
|
||||
}
|
||||
}
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,279 +0,0 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <unordered_map>
|
||||
|
||||
#include "Options.hpp"
|
||||
#include "google/protobuf/descriptor.h"
|
||||
#include "google/protobuf/descriptor.pb.h"
|
||||
#include "google/protobuf/io/printer.h"
|
||||
namespace struct_pb {
|
||||
namespace compiler {
|
||||
using namespace google::protobuf;
|
||||
using namespace google::protobuf::compiler;
|
||||
|
||||
inline bool is_map_entry(const google::protobuf::Descriptor *descriptor) {
|
||||
return descriptor->options().map_entry();
|
||||
}
|
||||
|
||||
void flatten_messages_in_file(
|
||||
const google::protobuf::FileDescriptor *file,
|
||||
std::vector<const google::protobuf::Descriptor *> *result);
|
||||
inline std::vector<const google::protobuf::Descriptor *>
|
||||
flatten_messages_in_file(const google::protobuf::FileDescriptor *file) {
|
||||
std::vector<const google::protobuf::Descriptor *> ret;
|
||||
flatten_messages_in_file(file, &ret);
|
||||
return ret;
|
||||
}
|
||||
template <typename F>
|
||||
void for_each_message(const google::protobuf::Descriptor *descriptor,
|
||||
F &&func) {
|
||||
for (int i = 0; i < descriptor->nested_type_count(); ++i) {
|
||||
for_each_message(descriptor->nested_type(i), std::forward<F &&>(func));
|
||||
}
|
||||
func(descriptor);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void for_each_message(const google::protobuf::FileDescriptor *descriptor,
|
||||
F &&func) {
|
||||
for (int i = 0; i < descriptor->message_type_count(); ++i) {
|
||||
for_each_message(descriptor->message_type(i), std::forward<F &&>(func));
|
||||
}
|
||||
}
|
||||
|
||||
inline void flatten_messages_in_file(
|
||||
const google::protobuf::FileDescriptor *file,
|
||||
std::vector<const google::protobuf::Descriptor *> *result) {
|
||||
for (int i = 0; i < file->message_type_count(); ++i) {
|
||||
for_each_message(file->message_type(i),
|
||||
[&](const google::protobuf::Descriptor *descriptor) {
|
||||
if (is_map_entry(descriptor)) {
|
||||
return;
|
||||
}
|
||||
result->push_back(descriptor);
|
||||
});
|
||||
}
|
||||
}
|
||||
inline std::string resolve_keyword(const std::string &name) {
|
||||
// clang-format off
|
||||
static std::set<std::string> keyword_set{
|
||||
//
|
||||
"NULL",
|
||||
"alignas",
|
||||
"alignof",
|
||||
"and",
|
||||
"and_eq",
|
||||
"asm",
|
||||
"auto",
|
||||
"bitand",
|
||||
"bitor",
|
||||
"bool",
|
||||
"break",
|
||||
"case",
|
||||
"catch",
|
||||
"char",
|
||||
"class",
|
||||
"compl",
|
||||
"const",
|
||||
"constexpr",
|
||||
"const_cast",
|
||||
"continue",
|
||||
"decltype",
|
||||
"default",
|
||||
"delete",
|
||||
"do",
|
||||
"double",
|
||||
"dynamic_cast",
|
||||
"else",
|
||||
"enum",
|
||||
"explicit",
|
||||
"export",
|
||||
"extern",
|
||||
"false",
|
||||
"float",
|
||||
"for",
|
||||
"friend",
|
||||
"goto",
|
||||
"if",
|
||||
"inline",
|
||||
"int",
|
||||
"long",
|
||||
"mutable",
|
||||
"namespace",
|
||||
"new",
|
||||
"noexcept",
|
||||
"not",
|
||||
"not_eq",
|
||||
"nullptr",
|
||||
"operator",
|
||||
"or",
|
||||
"or_eq",
|
||||
"private",
|
||||
"protected",
|
||||
"public",
|
||||
"register",
|
||||
"reinterpret_cast",
|
||||
"return",
|
||||
"short",
|
||||
"signed",
|
||||
"sizeof",
|
||||
"static",
|
||||
"static_assert",
|
||||
"static_cast",
|
||||
"struct",
|
||||
"switch",
|
||||
"template",
|
||||
"this",
|
||||
"thread_local",
|
||||
"throw",
|
||||
"true",
|
||||
"try",
|
||||
"typedef",
|
||||
"typeid",
|
||||
"typename",
|
||||
"union",
|
||||
"unsigned",
|
||||
"using",
|
||||
"virtual",
|
||||
"void",
|
||||
"volatile",
|
||||
"wchar_t",
|
||||
"while",
|
||||
"xor",
|
||||
"xor_eq",
|
||||
"char8_t",
|
||||
"char16_t",
|
||||
"char32_t",
|
||||
"concept",
|
||||
"consteval",
|
||||
"constinit",
|
||||
"co_await",
|
||||
"co_return",
|
||||
"co_yield",
|
||||
"requires",
|
||||
// typedef
|
||||
"uint32_t",
|
||||
"int32_t",
|
||||
"uint64_t",
|
||||
"int64_t",
|
||||
"size_t",
|
||||
"memset"
|
||||
};
|
||||
// clang-format on
|
||||
auto it = keyword_set.find(name);
|
||||
if (it == keyword_set.end()) {
|
||||
return name;
|
||||
}
|
||||
return name + "_";
|
||||
}
|
||||
inline std::string class_name(const google::protobuf::Descriptor *descriptor) {
|
||||
// assert(descriptor);
|
||||
auto parent = descriptor->containing_type();
|
||||
std::string ret;
|
||||
if (parent) {
|
||||
ret += class_name(parent) + "::";
|
||||
}
|
||||
ret += resolve_keyword(descriptor->name());
|
||||
return resolve_keyword(ret);
|
||||
}
|
||||
inline std::string enum_name(
|
||||
const google::protobuf::EnumDescriptor *descriptor) {
|
||||
auto parent = descriptor->containing_type();
|
||||
std::string ret;
|
||||
if (parent) {
|
||||
ret += class_name(parent) + "::";
|
||||
}
|
||||
ret += resolve_keyword(descriptor->name());
|
||||
return resolve_keyword(ret);
|
||||
}
|
||||
// https://stackoverflow.com/questions/2896600/how-to-replace-all-occurrences-of-a-character-in-string
|
||||
inline std::string ReplaceAll(std::string str, const std::string &from,
|
||||
const std::string &to) {
|
||||
size_t start_pos = 0;
|
||||
while ((start_pos = str.find(from, start_pos)) != std::string::npos) {
|
||||
str.replace(start_pos, from.length(), to);
|
||||
start_pos +=
|
||||
to.length(); // Handles case where 'to' is a substring of 'from'
|
||||
}
|
||||
return str;
|
||||
}
|
||||
inline std::string dots_to_colons(std::string name) {
|
||||
return ReplaceAll(name, ".", "::");
|
||||
}
|
||||
inline std::string get_namespace(const std::string &package) {
|
||||
if (package.empty()) {
|
||||
return "";
|
||||
}
|
||||
return "::" + dots_to_colons(package);
|
||||
}
|
||||
|
||||
inline std::string get_namespace(const google::protobuf::FileDescriptor *file,
|
||||
const Options &options) {
|
||||
if (file == options.f) {
|
||||
return get_namespace(options.ns);
|
||||
}
|
||||
else {
|
||||
return get_namespace(file->package());
|
||||
}
|
||||
}
|
||||
|
||||
inline std::string qualified_file_level_symbol(
|
||||
const google::protobuf::FileDescriptor *file, const std::string &name,
|
||||
const Options &options) {
|
||||
// if (options.ns.empty()) {
|
||||
// return absl::StrCat("::", name);
|
||||
// }
|
||||
return get_namespace(file, options) + "::" + name;
|
||||
}
|
||||
|
||||
inline std::string qualified_class_name(const google::protobuf::Descriptor *d,
|
||||
const Options &options) {
|
||||
return qualified_file_level_symbol(d->file(), class_name(d), options);
|
||||
}
|
||||
|
||||
inline std::string qualified_enum_name(
|
||||
const google::protobuf::EnumDescriptor *d, const Options &options) {
|
||||
return qualified_file_level_symbol(d->file(), enum_name(d), options);
|
||||
}
|
||||
|
||||
class Formatter {
|
||||
public:
|
||||
Formatter(google::protobuf::io::Printer *printer) : printer_(printer) {}
|
||||
void indent() const { printer_->Indent(); }
|
||||
void outdent() const { printer_->Outdent(); }
|
||||
template <typename... Args>
|
||||
void operator()(const char *format, const Args &...args) const {
|
||||
printer_->FormatInternal({ToString(args)...}, vars_, format);
|
||||
}
|
||||
|
||||
private:
|
||||
static std::string ToString(const std::string &s) { return s; }
|
||||
template <typename I, typename = typename std::enable_if<
|
||||
std::is_integral<I>::value>::type>
|
||||
static std::string ToString(I x) {
|
||||
return std::to_string(x);
|
||||
}
|
||||
|
||||
private:
|
||||
google::protobuf::io::Printer *printer_;
|
||||
std::map<std::string, std::string> vars_;
|
||||
};
|
||||
|
||||
class NamespaceOpener {
|
||||
public:
|
||||
NamespaceOpener(google::protobuf::io::Printer *p,
|
||||
const std::string &package = {});
|
||||
~NamespaceOpener();
|
||||
|
||||
public:
|
||||
void open() const;
|
||||
void close() const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> ns_;
|
||||
google::protobuf::io::Printer *p_;
|
||||
};
|
||||
std::string strip_proto(const std::string &filename);
|
||||
} // namespace compiler
|
||||
} // namespace struct_pb
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
#include <google/protobuf/compiler/plugin.h>
|
||||
|
||||
#include "StructGenerator.h"
|
||||
using namespace struct_pb::compiler;
|
||||
using namespace google::protobuf::compiler;
|
||||
int main(int argc, char* argv[]) {
|
||||
StructGenerator generator;
|
||||
return PluginMain(argc, argv, &generator);
|
||||
}
|
||||
|
|
@ -1,55 +1,39 @@
|
|||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests)
|
||||
find_package(Protobuf QUIET)
|
||||
if("${yaLanTingLibs_SOURCE_DIR}" STREQUAL "${CMAKE_SOURCE_DIR}")
|
||||
# If this is a subproject in ylt
|
||||
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/output/tests)
|
||||
else()
|
||||
# else find installed yalantinglibs
|
||||
cmake_minimum_required(VERSION 3.15)
|
||||
project(struct_pb_test)
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_INCLUDE_CURRENT_DIR ON)
|
||||
# if you have install ylt
|
||||
find_package(yalantinglibs REQUIRED)
|
||||
link_libraries(yalantinglibs::yalantinglibs)
|
||||
# else
|
||||
# include_directories(include)
|
||||
# include_directories(include/ylt/thirdparty)
|
||||
endif()
|
||||
|
||||
set(TEST_PROTO main.cpp)
|
||||
|
||||
if (Protobuf_FOUND)
|
||||
add_executable(test_struct_pb
|
||||
test_pb.cpp
|
||||
test_pb_oneof.cpp
|
||||
test_pb_benchmark_struct.cpp
|
||||
test_pb_bad_identifiers.cpp
|
||||
)
|
||||
target_sources(test_struct_pb PRIVATE
|
||||
main.cpp
|
||||
)
|
||||
add_test(NAME test_struct_pb COMMAND test_struct_pb)
|
||||
target_include_directories(test_struct_pb PUBLIC ${yaLanTingLibs_SOURCE_DIR}/src/struct_pack/benchmark)
|
||||
target_compile_definitions(test_struct_pb PRIVATE HAVE_PROTOBUF)
|
||||
target_link_libraries(test_struct_pb PRIVATE protobuf::libprotobuf)
|
||||
# generate .pb.cc .pb.h
|
||||
protobuf_generate_cpp(PROTO_SRCS
|
||||
PROTO_HDRS
|
||||
test_pb.proto
|
||||
data_def.proto
|
||||
)
|
||||
target_include_directories(test_struct_pb PUBLIC ${CMAKE_CURRENT_BINARY_DIR})
|
||||
target_sources(test_struct_pb PRIVATE
|
||||
${PROTO_SRCS}
|
||||
${PROTO_HDRS}
|
||||
)
|
||||
protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS
|
||||
STRUCT_PB_PROTO_HDRS
|
||||
test_pb.proto
|
||||
OPTION "generate_eq_op=true,namespace=test_struct_pb"
|
||||
)
|
||||
target_sources(test_struct_pb PRIVATE
|
||||
${STRUCT_PB_PROTO_SRCS}
|
||||
${STRUCT_PB_PROTO_HDRS}
|
||||
)
|
||||
protobuf_generate_struct_pb(STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS
|
||||
STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS
|
||||
data_def.proto
|
||||
OPTION "namespace=struct_pb_sample"
|
||||
)
|
||||
target_sources(test_struct_pb PRIVATE
|
||||
${STRUCT_PB_TEST_BENCHMARK_PROTO_SRCS}
|
||||
${STRUCT_PB_TEST_BENCHMARK_PROTO_HDRS}
|
||||
)
|
||||
protobuf_generate_struct_pb(STRUCT_PB_PROTO_SRCS2
|
||||
STRUCT_PB_PROTO_HDRS2
|
||||
test_bad_identifiers.proto
|
||||
test_large_enum_value.proto
|
||||
)
|
||||
target_sources(test_struct_pb PRIVATE
|
||||
${STRUCT_PB_PROTO_SRCS2}
|
||||
${STRUCT_PB_PROTO_HDRS2}
|
||||
)
|
||||
endif ()
|
||||
add_definitions(-DSTRUCT_PB_WITH_PROTO)
|
||||
message(STATUS "Found Protobuf: ${Protobuf_VERSION}")
|
||||
include_directories(${Protobuf_INCLUDE_DIRS})
|
||||
include_directories(${CMAKE_CURRENT_BINARY_DIR})
|
||||
set(PROTO_SRC_DIR ${CMAKE_CURRENT_SOURCE_DIR}/)
|
||||
file(GLOB PROTO_FILES ${PROTO_SRC_DIR}/*.proto)
|
||||
|
||||
protobuf_generate_cpp(PROTO_SRCS PROTO_HDRS ${PROTO_FILES})
|
||||
# message(STATUS "Proto source files: ${PROTO_SRCS}")
|
||||
# message(STATUS "Proto header files: ${PROTO_HDRS}")
|
||||
add_executable(struct_pb_test ${PROTO_SRCS} ${TEST_PROTO})
|
||||
target_link_libraries(struct_pb_test PRIVATE protobuf::libprotobuf)
|
||||
add_test(NAME struct_pb_test COMMAND struct_pb_test)
|
||||
else()
|
||||
add_executable(struct_pb_test ${TEST_PROTO})
|
||||
add_test(NAME struct_pb_test COMMAND struct_pb_test)
|
||||
endif()
|
||||
|
|
@ -37,17 +37,6 @@ message Monsters {
|
|||
repeated Monster monsters = 1;
|
||||
}
|
||||
|
||||
message rect32 {
|
||||
int32 x = 1;
|
||||
int32 y = 2;
|
||||
int32 width = 3;
|
||||
int32 height = 4;
|
||||
}
|
||||
|
||||
message rect32s {
|
||||
repeated rect32 rect32_list = 1;
|
||||
}
|
||||
|
||||
message person {
|
||||
int32 id = 1;
|
||||
string name = 2;
|
||||
|
|
@ -57,4 +46,11 @@ message person {
|
|||
|
||||
message persons {
|
||||
repeated person person_list = 1;
|
||||
}
|
||||
|
||||
message bench_int32 {
|
||||
int32 a = 1;
|
||||
int32 b = 2;
|
||||
int32 c = 3;
|
||||
int32 d = 4;
|
||||
}
|
||||
|
|
@ -1,78 +0,0 @@
|
|||
#pragma once
|
||||
#include <optional>
|
||||
|
||||
#include "data_def.struct_pb.h"
|
||||
#include "hex_printer.hpp"
|
||||
#include "test_pb.struct_pb.h"
|
||||
#include "ylt/struct_pb.hpp"
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "google/protobuf/repeated_field.h"
|
||||
#endif
|
||||
|
||||
template <typename T, typename Pred = std::equal_to<T>>
|
||||
void check_self(const T& t, std::optional<std::string> buf_opt = {}) {
|
||||
auto size = struct_pb::internal::get_needed_size(t);
|
||||
if (buf_opt.has_value()) {
|
||||
REQUIRE(buf_opt.value().size() == size);
|
||||
}
|
||||
auto b = struct_pb::serialize<std::string>(t);
|
||||
if (buf_opt.has_value()) {
|
||||
CHECK(hex_helper(buf_opt.value()) == hex_helper(b));
|
||||
}
|
||||
T d_t{};
|
||||
auto ok = struct_pb::deserialize_to(d_t, b);
|
||||
REQUIRE(ok);
|
||||
CHECK(Pred()(t, d_t));
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <typename T, typename PB_T>
|
||||
struct PB_equal {
|
||||
constexpr bool operator()(const T& t, const PB_T& pb_t) const {
|
||||
return t == pb_t;
|
||||
}
|
||||
};
|
||||
template <typename T, typename PB_T, typename Pred = PB_equal<T, PB_T>>
|
||||
void check_with_protobuf(const T& t, const PB_T& pb_t) {
|
||||
auto pb_buf = pb_t.SerializeAsString();
|
||||
auto size = struct_pb::internal::get_needed_size(t);
|
||||
REQUIRE(size == pb_buf.size());
|
||||
|
||||
std::string b = struct_pb::serialize<std::string>(t);
|
||||
CHECK(hex_helper(b) == hex_helper(pb_buf));
|
||||
|
||||
CHECK(Pred()(t, pb_t));
|
||||
T d_t{};
|
||||
auto ok = struct_pb::deserialize_to(d_t, b);
|
||||
REQUIRE(ok);
|
||||
CHECK(Pred()(d_t, pb_t));
|
||||
}
|
||||
template <typename T, typename U>
|
||||
bool operator==(const std::vector<T>& a,
|
||||
const google::protobuf::RepeatedPtrField<U>& b) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
auto sz = a.size();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (!PB_equal<T, U>()(a[i], b.at(i))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T, typename U>
|
||||
bool operator==(const std::vector<T>& a,
|
||||
const google::protobuf::RepeatedField<U>& b) {
|
||||
if (a.size() != b.size()) {
|
||||
return false;
|
||||
}
|
||||
auto sz = a.size();
|
||||
for (int i = 0; i < sz; ++i) {
|
||||
if (a[i] != b.at(i)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
#pragma once
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
// useful for debugging
|
||||
inline void print_hex(uint8_t v) {
|
||||
static std::string hex = "0123456789abcedf";
|
||||
if (v < 16) {
|
||||
std::cout << "0";
|
||||
std::cout << hex[v];
|
||||
}
|
||||
else {
|
||||
std::size_t first = v / 16;
|
||||
std::size_t last = v % 16;
|
||||
std::cout << hex[first] << hex[last];
|
||||
}
|
||||
}
|
||||
inline void print_hex(std::string_view sv) {
|
||||
for (char ch : sv) {
|
||||
uint8_t v = static_cast<uint8_t>(ch);
|
||||
print_hex(v);
|
||||
std::cout << " ";
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
struct hex_helper {
|
||||
hex_helper(std::string_view sv) : sv(sv) {}
|
||||
friend std::ostream& operator<<(std::ostream& os, const hex_helper& helper) {
|
||||
static std::string hex = "0123456789abcedf";
|
||||
auto to_hex = [&os](std::string_view hex, uint8_t v) {
|
||||
if (v < 16) {
|
||||
os << "0";
|
||||
os << hex[v];
|
||||
}
|
||||
else {
|
||||
std::size_t first = v / 16;
|
||||
std::size_t last = v % 16;
|
||||
os << hex[first] << hex[last];
|
||||
}
|
||||
};
|
||||
for (char ch : helper.sv) {
|
||||
uint8_t v = static_cast<uint8_t>(ch);
|
||||
to_hex(hex, v);
|
||||
os << " ";
|
||||
}
|
||||
return os;
|
||||
}
|
||||
bool operator==(const hex_helper&) const = default;
|
||||
std::string_view sv;
|
||||
};
|
||||
File diff suppressed because it is too large
Load Diff
|
|
@ -1,191 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Author: kenton@google.com (Kenton Varda)
|
||||
// Based on original Protocol Buffers design by
|
||||
// Sanjay Ghemawat, Jeff Dean, and others.
|
||||
//
|
||||
// This file tests that various identifiers work as field and type names even
|
||||
// though the same identifiers are used internally by the C++ code generator.
|
||||
|
||||
// LINT: LEGACY_NAMES
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
// Some generic_services option(s) added automatically.
|
||||
// See: http://go/proto2-generic-services-default
|
||||
option cc_generic_services = true; // auto-added
|
||||
|
||||
// We don't put this in a package within proto2 because we need to make sure
|
||||
// that the generated code doesn't depend on being in the proto2 namespace.
|
||||
package protobuf_unittest;
|
||||
|
||||
// Test that fields can have names like "input" and "i" which are also used
|
||||
// internally by the code generator for local variables.
|
||||
message TestConflictingSymbolNames {
|
||||
message BuildDescriptors {}
|
||||
message TypeTraits {}
|
||||
|
||||
optional int32 input = 1;
|
||||
optional int32 output = 2;
|
||||
optional string length = 3;
|
||||
repeated int32 i = 4;
|
||||
repeated string new_element = 5 [ctype = STRING_PIECE];
|
||||
optional int32 total_size = 6;
|
||||
optional int32 tag = 7;
|
||||
|
||||
enum TestEnum {
|
||||
FOO = 0;
|
||||
}
|
||||
message Data1 {
|
||||
repeated int32 data = 1;
|
||||
}
|
||||
message Data2 {
|
||||
repeated TestEnum data = 1;
|
||||
}
|
||||
message Data3 {
|
||||
repeated string data = 1;
|
||||
}
|
||||
message Data4 {
|
||||
repeated Data4 data = 1;
|
||||
}
|
||||
message Data5 {
|
||||
repeated string data = 1 [ctype = STRING_PIECE];
|
||||
}
|
||||
message Data6 {
|
||||
repeated string data = 1 [ctype = CORD];
|
||||
}
|
||||
|
||||
optional int32 source = 8;
|
||||
optional int32 value = 9;
|
||||
optional int32 file = 10;
|
||||
optional int32 from = 11;
|
||||
optional int32 handle_uninterpreted = 12;
|
||||
repeated int32 index = 13;
|
||||
optional int32 controller = 14;
|
||||
optional int32 already_here = 15;
|
||||
|
||||
optional uint32 uint32 = 16;
|
||||
optional uint32 uint32_t = 41;
|
||||
optional uint64 uint64 = 17;
|
||||
optional uint32 uint64_t = 42;
|
||||
optional string string = 18;
|
||||
optional int32 memset = 19;
|
||||
optional int32 int32 = 20;
|
||||
optional int32 int32_t = 43;
|
||||
optional int64 int64 = 21;
|
||||
optional int64 int64_t = 44;
|
||||
optional int64 size_t = 45;
|
||||
|
||||
optional uint32 cached_size = 22;
|
||||
optional uint32 extensions = 23;
|
||||
optional uint32 bit = 24;
|
||||
optional uint32 bits = 25;
|
||||
optional uint32 offsets = 26;
|
||||
optional uint32 reflection = 27;
|
||||
|
||||
message Cord {}
|
||||
optional string some_cord = 28 [ctype = CORD];
|
||||
|
||||
message StringPiece {}
|
||||
optional string some_string_piece = 29 [ctype = STRING_PIECE];
|
||||
|
||||
// Some keywords.
|
||||
optional uint32 int = 30;
|
||||
optional uint32 friend = 31;
|
||||
optional uint32 class = 37;
|
||||
optional uint32 typedecl = 39;
|
||||
optional uint32 auto = 40;
|
||||
|
||||
// The generator used to #define a macro called "DO" inside the .cc file.
|
||||
message DO {}
|
||||
optional DO do = 32;
|
||||
|
||||
// Some template parameter names for extensions.
|
||||
optional int32 field_type = 33;
|
||||
optional bool is_packed = 34;
|
||||
|
||||
// test conflicting release_$name$. "length" and "do" field in this message
|
||||
// must remain string or message fields to make the test valid.
|
||||
optional string release_length = 35;
|
||||
// A more extreme case, the field name "do" here is a keyword, which will be
|
||||
// escaped to "do_" already. Test there is no conflict even with escaped field
|
||||
// names.
|
||||
optional DO release_do = 36;
|
||||
|
||||
// For clashing local variables in Serialize and ByteSize calculation.
|
||||
optional string target = 38;
|
||||
|
||||
extensions 1000 to max; // NO_PROTO3
|
||||
}
|
||||
|
||||
message TestConflictingSymbolNamesExtension { // NO_PROTO3
|
||||
extend TestConflictingSymbolNames { // NO_PROTO3
|
||||
repeated int32 repeated_int32_ext = 20423638 [packed = true]; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
message TestConflictingEnumNames { // NO_PROTO3
|
||||
enum while { // NO_PROTO3
|
||||
default = 0; // NO_PROTO3
|
||||
and = 1; // NO_PROTO3
|
||||
class = 2; // NO_PROTO3
|
||||
int = 3; // NO_PROTO3
|
||||
typedef = 4; // NO_PROTO3
|
||||
XOR = 5; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
optional while conflicting_enum = 1; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
enum bool { // NO_PROTO3
|
||||
default = 0; // NO_PROTO3
|
||||
NOT_EQ = 1; // NO_PROTO3
|
||||
volatile = 2; // NO_PROTO3
|
||||
return = 3; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
message DummyMessage {}
|
||||
|
||||
message NULL {
|
||||
optional int32 int = 1;
|
||||
}
|
||||
|
||||
extend TestConflictingSymbolNames { // NO_PROTO3
|
||||
optional int32 void = 314253; // NO_PROTO3
|
||||
} // NO_PROTO3
|
||||
|
||||
// Message names that could conflict.
|
||||
message Shutdown {}
|
||||
message TableStruct {}
|
||||
|
||||
service TestConflictingMethodNames {
|
||||
rpc Closure(DummyMessage) returns (DummyMessage);
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
// Protocol Buffers - Google's data interchange format
|
||||
// Copyright 2008 Google Inc. All rights reserved.
|
||||
// https://developers.google.com/protocol-buffers/
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, are permitted provided that the following conditions are
|
||||
// met:
|
||||
//
|
||||
// * Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
// * Redistributions in binary form must reproduce the above
|
||||
// copyright notice, this list of conditions and the following disclaimer
|
||||
// in the documentation and/or other materials provided with the
|
||||
// distribution.
|
||||
// * Neither the name of Google Inc. nor the names of its
|
||||
// contributors may be used to endorse or promote products derived from
|
||||
// this software without specific prior written permission.
|
||||
//
|
||||
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
||||
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
||||
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
||||
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
||||
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
||||
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
||||
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
// Test that proto2 compiler can generate valid code when the enum value
|
||||
// is INT_MAX. Note that this is a compile-only test and this proto is not
|
||||
// referenced in any C++ code.
|
||||
syntax = "proto2";
|
||||
|
||||
package protobuf_unittest;
|
||||
|
||||
message TestLargeEnumValue {
|
||||
enum EnumWithLargeValue {
|
||||
VALUE_1 = 1;
|
||||
VALUE_MAX = 0x7fffffff;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,851 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
|
||||
#include <valarray>
|
||||
|
||||
#include "doctest.h"
|
||||
#include "helper.hpp"
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "test_pb.pb.h"
|
||||
#endif
|
||||
using namespace doctest;
|
||||
using namespace struct_pb;
|
||||
|
||||
TEST_SUITE_BEGIN("test pb");
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::Test1, Test1> {
|
||||
bool operator()(const test_struct_pb::Test1& t, const Test1& pb_t) const {
|
||||
return t.a == pb_t.a();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing test_struct_pb::Test1") {
|
||||
test_struct_pb::Test1 t{};
|
||||
SUBCASE("empty") { check_self(t); }
|
||||
SUBCASE("has value") {
|
||||
std::string buf{0x08, (char)0x96, 0x01};
|
||||
t.a = 150;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test1 pb_t;
|
||||
pb_t.set_a(150);
|
||||
auto pb_buf = pb_t.SerializeAsString();
|
||||
REQUIRE(pb_buf == buf);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
SUBCASE("negative") {
|
||||
{
|
||||
// an example for check arm char
|
||||
std::string buf{0x08, (char)0xff, (char)0xff, (char)0xff,
|
||||
(char)0xff, (char)0xff, (char)0xff, (char)0xff,
|
||||
(char)0xff, (char)0xff, 0x01};
|
||||
test_struct_pb::Test1 t{.a = -1};
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
// for debug
|
||||
Test1 pb_t;
|
||||
pb_t.set_a(-1);
|
||||
auto s = pb_t.SerializeAsString();
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
for (int32_t i = -1; i > INT16_MIN + 1; i *= 2) {
|
||||
test_struct_pb::Test1 t{.a = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test1 pb_t;
|
||||
pb_t.set_a(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::Test2, Test2> {
|
||||
bool operator()(const test_struct_pb::Test2& t, const Test2& pb_t) const {
|
||||
return t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing test_struct_pb::Test2") {
|
||||
test_struct_pb::Test2 t{};
|
||||
SUBCASE("empty") { check_self(t); }
|
||||
SUBCASE("has value") {
|
||||
std::string buf{0x12, 0x07};
|
||||
std::string s = "testing";
|
||||
buf += s;
|
||||
t.b = s;
|
||||
check_self(t, buf);
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test2 pb_t;
|
||||
pb_t.set_b(s);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
namespace std {
|
||||
template <>
|
||||
struct equal_to<test_struct_pb::Test3> {
|
||||
bool operator()(const test_struct_pb::Test3& lhs,
|
||||
const test_struct_pb::Test3& rhs) const {
|
||||
if (lhs.c && rhs.c) {
|
||||
return equal_to<test_struct_pb::Test1>()(*lhs.c, *rhs.c);
|
||||
}
|
||||
if (!lhs.c && !rhs.c) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::Test3, Test3> {
|
||||
bool operator()(const test_struct_pb::Test3& t, const Test3& pb_t) const {
|
||||
if (t.c && pb_t.has_c()) {
|
||||
return PB_equal<test_struct_pb::Test1, Test1>()(*t.c, pb_t.c());
|
||||
}
|
||||
if (!t.c && !pb_t.has_c()) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing test_struct_pb::Test3") {
|
||||
test_struct_pb::Test3 t{};
|
||||
SUBCASE("empty") { check_self(t); }
|
||||
SUBCASE("has value") {
|
||||
std::string buf{0x1a, 0x03, 0x08, (char)0x96, 0x01};
|
||||
t.c = std::make_unique<test_struct_pb::Test1>(
|
||||
test_struct_pb::Test1{.a = 150});
|
||||
check_self(t, buf);
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test3 pb_t;
|
||||
auto pb_c = new Test1;
|
||||
pb_c->set_a(150);
|
||||
pb_t.set_allocated_c(pb_c);
|
||||
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::Test4, Test4> {
|
||||
bool operator()(const test_struct_pb::Test4& t, const Test4& pb_t) const {
|
||||
return t.e == pb_t.e();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing test_struct_pb::Test4") {
|
||||
test_struct_pb::Test4 t{};
|
||||
SUBCASE("empty") { check_self(t); }
|
||||
SUBCASE("string empty") {
|
||||
std::string buf{0x2a, 0x01, 0x01};
|
||||
t.e = {1};
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test4 pb_t;
|
||||
pb_t.add_e(1);
|
||||
auto pb_buf = pb_t.SerializeAsString();
|
||||
REQUIRE(pb_buf == buf);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("repeated empty") {
|
||||
// [4] 22 2 68 69
|
||||
std::string buf{0x22, 0x02, 0x68, 0x69};
|
||||
std::string s = "hi";
|
||||
t.d = s;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test4 pb_t;
|
||||
pb_t.set_d(s);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("has value") {
|
||||
std::string buf{0x22, 0x05, 0x68, 0x65, 0x6c, 0x6c,
|
||||
0x6f, 0x2a, 0x03, 0x01, 0x02, 0x03};
|
||||
// why document write
|
||||
// 220568656c6c6f280128022803
|
||||
// while my pb c++ code generated
|
||||
// 34 5 'h' 'e' 'l' 'l' 'o' 42 3 1 2 3
|
||||
// 22 5 68 65 6c 6c 6f 2a 3 1 2 3
|
||||
t.d = "hello";
|
||||
t.e = {1, 2, 3};
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
Test4 pb_t;
|
||||
pb_t.set_d("hello");
|
||||
pb_t.add_e(1);
|
||||
pb_t.add_e(2);
|
||||
pb_t.add_e(3);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestDouble, MyTestDouble> {
|
||||
bool operator()(const test_struct_pb::MyTestDouble& t,
|
||||
const MyTestDouble& pb_t) const {
|
||||
std::valarray<double> ts{t.a, t.b, t.c};
|
||||
std::valarray<double> pb_ts{pb_t.a(), pb_t.b(), pb_t.c()};
|
||||
return (std::abs(ts - pb_ts) < 0.00005f).min();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing double") {
|
||||
test_struct_pb::MyTestDouble t{.a = 123.456, .b = 0, .c = -678.123};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestDouble pb_t;
|
||||
pb_t.set_a(t.a);
|
||||
pb_t.set_b(t.b);
|
||||
pb_t.set_c(t.c);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestFloat, MyTestFloat> {
|
||||
bool operator()(const test_struct_pb::MyTestFloat& t,
|
||||
const MyTestFloat& pb_t) const {
|
||||
std::valarray<float> ts{t.a, t.b, t.c, t.d, t.e};
|
||||
std::valarray<float> pb_ts{pb_t.a(), pb_t.b(), pb_t.c(), pb_t.d(),
|
||||
pb_t.e()};
|
||||
return (std::abs(ts - pb_ts) < 0.00005f).min();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing float") {
|
||||
// [20] 15 00 00 80 3f 1d 00 00 80 bf 25 b6 f3 9d 3f 2d 00 04 f1 47
|
||||
std::string buf{0x15, 0x00, 0x00, (char)0x80, 0x3f,
|
||||
0x1d, 0x00, 0x00, (char)0x80, (char)0xbf,
|
||||
0x25, (char)0xb6, (char)0xf3, (char)0x9d, 0x3f,
|
||||
0x2d, 0x00, 0x04, (char)0xf1, 0x47};
|
||||
test_struct_pb::MyTestFloat t{
|
||||
.a = 0, .b = 1, .c = -1, .d = 1.234, .e = 1.234e5};
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestFloat pb_t;
|
||||
pb_t.set_a(0);
|
||||
pb_t.set_b(1);
|
||||
pb_t.set_c(-1);
|
||||
pb_t.set_d(1.234);
|
||||
pb_t.set_e(1.234e5);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestInt32, MyTestInt32> {
|
||||
bool operator()(const test_struct_pb::MyTestInt32& t,
|
||||
const MyTestInt32& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing int32") {
|
||||
std::string buf{0x08, (char)0x80, 0x01};
|
||||
test_struct_pb::MyTestInt32 t;
|
||||
t.a = 128;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestInt32 pb_t;
|
||||
pb_t.set_a(128);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestInt64, MyTestInt64> {
|
||||
bool operator()(const test_struct_pb::MyTestInt64& t,
|
||||
const MyTestInt64& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing int64") {
|
||||
int64_t max_val = 4;
|
||||
max_val *= INT32_MAX;
|
||||
for (int64_t i = 1; i < max_val; i *= -2) {
|
||||
test_struct_pb::MyTestInt64 t{.a = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestInt64 pb_t;
|
||||
pb_t.set_a(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestUint32, MyTestUint32> {
|
||||
bool operator()(const test_struct_pb::MyTestUint32& t,
|
||||
const MyTestUint32& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing uint32") {
|
||||
int32_t max_val = 4;
|
||||
max_val *= INT16_MAX;
|
||||
for (uint32_t i = 1; i < max_val; i *= 2) {
|
||||
test_struct_pb::MyTestUint32 t{.a = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestUint32 pb_t;
|
||||
pb_t.set_a(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestUint64, MyTestUint64> {
|
||||
bool operator()(const test_struct_pb::MyTestUint64& t,
|
||||
const MyTestUint64& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing uint64") {
|
||||
int64_t max_val = 4;
|
||||
max_val *= INT32_MAX;
|
||||
for (uint64_t i = 1; i < max_val; i *= 2) {
|
||||
test_struct_pb::MyTestUint64 t{.a = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestUint64 pb_t;
|
||||
pb_t.set_a(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestEnum, MyTestEnum> {
|
||||
bool operator()(const test_struct_pb::MyTestEnum& t,
|
||||
const MyTestEnum& pb_t) const {
|
||||
return static_cast<uint32_t>(t.color) ==
|
||||
static_cast<uint32_t>(pb_t.color());
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing enum") {
|
||||
SUBCASE("Red") {
|
||||
std::string buf;
|
||||
test_struct_pb::MyTestEnum t{};
|
||||
t.color = test_struct_pb::MyTestEnum::Color::Red;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestEnum pb_t;
|
||||
pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Red);
|
||||
auto pb_buf = pb_t.SerializeAsString();
|
||||
REQUIRE(hex_helper(pb_buf) == hex_helper(buf));
|
||||
MyTestEnum pb_d_t;
|
||||
auto ok = pb_d_t.ParseFromArray(pb_buf.data(), pb_buf.size());
|
||||
REQUIRE(ok);
|
||||
CHECK(pb_d_t.IsInitialized());
|
||||
CHECK(pb_d_t.color() == pb_t.color());
|
||||
auto c = pb_d_t.color();
|
||||
CHECK(c == MyTestEnum_Color::MyTestEnum_Color_Red);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("Green") {
|
||||
std::string buf{0x30, 0x01};
|
||||
test_struct_pb::MyTestEnum t{};
|
||||
t.color = test_struct_pb::MyTestEnum::Color::Green;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestEnum pb_t;
|
||||
pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Green);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("Blue") {
|
||||
std::string buf{0x30, 0x02};
|
||||
test_struct_pb::MyTestEnum t{};
|
||||
t.color = test_struct_pb::MyTestEnum::Color::Blue;
|
||||
check_self(t, buf);
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestEnum pb_t;
|
||||
pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Blue);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("Enum127") {
|
||||
std::string buf{0x30, (char)0x7f};
|
||||
test_struct_pb::MyTestEnum t{};
|
||||
t.color = test_struct_pb::MyTestEnum::Color::Enum127;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestEnum pb_t;
|
||||
pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum127);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("Enum128") {
|
||||
std::string buf{0x30, (char)0x80, 0x01};
|
||||
test_struct_pb::MyTestEnum t{};
|
||||
t.color = test_struct_pb::MyTestEnum::Color::Enum128;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestEnum pb_t;
|
||||
pb_t.set_color(MyTestEnum_Color::MyTestEnum_Color_Enum128);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestRepeatedMessage, MyTestRepeatedMessage> {
|
||||
bool operator()(const test_struct_pb::MyTestRepeatedMessage& t,
|
||||
const MyTestRepeatedMessage& pb_t) const {
|
||||
return t.fs == pb_t.fs();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing nested repeated message") {
|
||||
SUBCASE("one") {
|
||||
test_struct_pb::MyTestRepeatedMessage t{};
|
||||
t.fs = {{1, 2, 3}};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestRepeatedMessage pb_t;
|
||||
{
|
||||
auto f1 = pb_t.add_fs();
|
||||
f1->set_a(1);
|
||||
f1->set_b(2);
|
||||
f1->set_c(3);
|
||||
}
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("two") {
|
||||
test_struct_pb::MyTestRepeatedMessage t{};
|
||||
t.fs = {{1, 2, 3}, {4, 5, 6}};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestRepeatedMessage pb_t;
|
||||
{
|
||||
auto f1 = pb_t.add_fs();
|
||||
f1->set_a(1);
|
||||
f1->set_b(2);
|
||||
f1->set_c(3);
|
||||
}
|
||||
{
|
||||
auto f1 = pb_t.add_fs();
|
||||
f1->set_a(4);
|
||||
f1->set_b(5);
|
||||
f1->set_c(6);
|
||||
}
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestSint32, MyTestSint32> {
|
||||
bool operator()(const test_struct_pb::MyTestSint32& t,
|
||||
const MyTestSint32& pb_t) const {
|
||||
return t.a == pb_t.a();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing sint32") {
|
||||
SUBCASE("-1") {
|
||||
std::string buf{0x08, 0x01};
|
||||
test_struct_pb::MyTestSint32 t{};
|
||||
t.a = -1;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint32 pb_t;
|
||||
pb_t.set_a(-1);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("1") {
|
||||
test_struct_pb::MyTestSint32 t{};
|
||||
t.a = 1;
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint32 pb_t;
|
||||
pb_t.set_a(1);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("128") {
|
||||
std::string buf{0x08, (char)0x80, 0x02};
|
||||
test_struct_pb::MyTestSint32 t{};
|
||||
t.a = 128;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint32 pb_t;
|
||||
pb_t.set_a(128);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
SUBCASE("range") {
|
||||
for (int32_t i = INT16_MAX; i > INT16_MIN + 1; --i) {
|
||||
test_struct_pb::MyTestSint32 t{.a = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint32 pb_t;
|
||||
pb_t.set_a(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestSint64, MyTestSint64> {
|
||||
bool operator()(const test_struct_pb::MyTestSint64& t,
|
||||
const MyTestSint64& pb_t) const {
|
||||
return t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing sint64") {
|
||||
SUBCASE("-1") {
|
||||
std::string buf{0x10, 0x01};
|
||||
test_struct_pb::MyTestSint64 t{};
|
||||
t.b = -1;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint64 pb_t;
|
||||
pb_t.set_b(-1);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("128") {
|
||||
std::string buf{0x10, (char)0x80, 0x02};
|
||||
test_struct_pb::MyTestSint64 t{};
|
||||
t.b = 128;
|
||||
check_self(t, buf);
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint64 pb_t;
|
||||
pb_t.set_b(128);
|
||||
check_with_protobuf(t, pb_t);
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
SUBCASE("range") {
|
||||
for (int64_t i = -1; i > INT32_MIN + 1; i *= -2) {
|
||||
test_struct_pb::MyTestSint64 t{.b = i};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSint64 pb_t;
|
||||
pb_t.set_b(i);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestMap, MyTestMap> {
|
||||
bool operator()(const test_struct_pb::MyTestMap& t,
|
||||
const MyTestMap& pb_t) const {
|
||||
if (t.e.size() != pb_t.e_size()) {
|
||||
return false;
|
||||
}
|
||||
for (const auto& [k, v] : pb_t.e()) {
|
||||
auto it = t.e.find(k);
|
||||
if (it == t.e.end()) {
|
||||
return false;
|
||||
}
|
||||
if (it->second != v) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing map") {
|
||||
SUBCASE("one entry") {
|
||||
std::string buf{0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01};
|
||||
test_struct_pb::MyTestMap t;
|
||||
t.e["a"] = 1;
|
||||
check_self(t, buf);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestMap pb_t;
|
||||
auto& pb_m = *pb_t.mutable_e();
|
||||
pb_m["a"] = 1;
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("two entry") {
|
||||
std::string buf{
|
||||
0x1a, 0x0a, 0x0a, 0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10,
|
||||
(char)0x9a, 0x05, 0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01,
|
||||
};
|
||||
std::string buf2{
|
||||
0x1a, 0x05, 0x0a, 0x01, 0x61, 0x10, 0x01, 0x1a, 0x0a, 0x0a,
|
||||
0x05, 0x68, 0x65, 0x6c, 0x6c, 0x6f, 0x10, (char)0x9a, 0x05,
|
||||
};
|
||||
test_struct_pb::MyTestMap t;
|
||||
t.e["a"] = 1;
|
||||
t.e["hello"] = 666;
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestMap pb_t;
|
||||
auto& pb_m = *pb_t.mutable_e();
|
||||
pb_m["a"] = 1;
|
||||
pb_m["hello"] = 666;
|
||||
auto pb_buf = pb_t.SerializeAsString();
|
||||
|
||||
CHECK(buf.size() == pb_buf.size());
|
||||
REQUIRE((buf == pb_buf || buf2 == pb_buf));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestFixed32, MyTestFixed32> {
|
||||
bool operator()(const test_struct_pb::MyTestFixed32& t,
|
||||
const MyTestFixed32& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing fixed32") {
|
||||
test_struct_pb::MyTestFixed32 t{};
|
||||
SUBCASE("single fixed") {
|
||||
t.a = 888;
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestFixed32 pb_t;
|
||||
pb_t.set_a(888);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
SUBCASE("only repeated") {
|
||||
t.b = {5, 4, 3, 2, 1};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestFixed32 pb_t;
|
||||
pb_t.add_b(5);
|
||||
pb_t.add_b(4);
|
||||
pb_t.add_b(3);
|
||||
pb_t.add_b(2);
|
||||
pb_t.add_b(1);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestFixed64, MyTestFixed64> {
|
||||
bool operator()(const test_struct_pb::MyTestFixed64& t,
|
||||
const MyTestFixed64& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing fixed64") {
|
||||
using T = uint64_t;
|
||||
T max_val = 4;
|
||||
max_val *= INT32_MAX;
|
||||
for (T i = 1; i < max_val; i *= 2) {
|
||||
test_struct_pb::MyTestFixed64 t{.a = i};
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestFixed64 pb_t;
|
||||
pb_t.set_a(i);
|
||||
#endif
|
||||
for (T j = 1; j <= i; j *= 2) {
|
||||
#ifdef HAVE_PROTOBUF
|
||||
pb_t.add_b(j * 3);
|
||||
#endif
|
||||
t.b.push_back(j * 3);
|
||||
}
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestSfixed32, MyTestSfixed32> {
|
||||
bool operator()(const test_struct_pb::MyTestSfixed32& t,
|
||||
const MyTestSfixed32& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing sfixed32") {
|
||||
using T = int32_t;
|
||||
T max_val = 4;
|
||||
max_val *= INT16_MAX;
|
||||
for (T i = 1; i < max_val; i *= -2) {
|
||||
test_struct_pb::MyTestSfixed32 t{.a = i};
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSfixed32 pb_t;
|
||||
pb_t.set_a(i);
|
||||
#endif
|
||||
for (T j = 1; j <= i; j *= -2) {
|
||||
#ifdef HAVE_PROTOBUF
|
||||
pb_t.add_b(j * -3);
|
||||
#endif
|
||||
t.b.push_back(j * -3);
|
||||
}
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestSfixed64, MyTestSfixed64> {
|
||||
bool operator()(const test_struct_pb::MyTestSfixed64& t,
|
||||
const MyTestSfixed64& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing sfixed64") {
|
||||
using T = int64_t;
|
||||
T max_val = 4;
|
||||
max_val *= INT32_MAX;
|
||||
for (T i = 1; i < max_val; i *= -2) {
|
||||
test_struct_pb::MyTestSfixed64 t{.a = i};
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestSfixed64 pb_t;
|
||||
pb_t.set_a(i);
|
||||
#endif
|
||||
for (T j = 1; j <= i; j *= -2) {
|
||||
#ifdef HAVE_PROTOBUF
|
||||
pb_t.add_b(j * -3);
|
||||
#endif
|
||||
t.b.push_back(j * -3);
|
||||
}
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestFieldNumberRandom,
|
||||
MyTestFieldNumberRandom> {
|
||||
bool operator()(const test_struct_pb::MyTestFieldNumberRandom& t,
|
||||
const MyTestFieldNumberRandom& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() &&
|
||||
t.f == pb_t.f() && std::abs(t.d - pb_t.d()) < 0.00005f &&
|
||||
std::abs(t.e - pb_t.e()) < 0.00005f;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing random field number") {
|
||||
test_struct_pb::MyTestFieldNumberRandom t{.a = 666,
|
||||
.b = 999,
|
||||
.c = "random",
|
||||
.d = 3.14,
|
||||
.e = 3344.123,
|
||||
.f = {5, 4, 3, 2, 1}};
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestFieldNumberRandom pb_t;
|
||||
pb_t.set_a(666);
|
||||
pb_t.set_b(999);
|
||||
pb_t.set_c("random");
|
||||
pb_t.set_d(3.14);
|
||||
pb_t.set_e(3344.123);
|
||||
pb_t.add_f(5);
|
||||
pb_t.add_f(4);
|
||||
pb_t.add_f(3);
|
||||
pb_t.add_f(2);
|
||||
pb_t.add_f(1);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::MyTestAll, MyTestAll> {
|
||||
bool operator()(const test_struct_pb::MyTestAll& t,
|
||||
const MyTestAll& pb_t) const {
|
||||
return t.a == pb_t.a() && t.b == pb_t.b() && t.c == pb_t.c() &&
|
||||
t.d == pb_t.d() && t.e == pb_t.e() && t.f == pb_t.f() &&
|
||||
t.g == pb_t.g() && t.h == pb_t.h() && t.i == pb_t.i() &&
|
||||
t.j == pb_t.j() && t.k == pb_t.k() && t.l == pb_t.l() &&
|
||||
t.m == pb_t.m() && t.n == pb_t.n() && t.o == pb_t.o();
|
||||
}
|
||||
};
|
||||
#endif
|
||||
TEST_CASE("testing all") {
|
||||
test_struct_pb::MyTestAll t{};
|
||||
|
||||
t.a = -100;
|
||||
t.b = -200;
|
||||
t.c = -300;
|
||||
t.d = -2378;
|
||||
t.e = 2323;
|
||||
t.f = 255;
|
||||
t.g = -890;
|
||||
t.h = -2369723;
|
||||
t.i = -23234;
|
||||
t.j = -239223423;
|
||||
t.k = 9232983;
|
||||
t.l = 237982374432;
|
||||
t.m = true;
|
||||
t.n = "testing all types";
|
||||
t.o = "\1\2\3\4\5\t\n666";
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
MyTestAll pb_t;
|
||||
pb_t.set_a(t.a);
|
||||
pb_t.set_b(t.b);
|
||||
pb_t.set_c(t.c);
|
||||
pb_t.set_d(t.d);
|
||||
pb_t.set_e(t.e);
|
||||
pb_t.set_f(t.f);
|
||||
pb_t.set_g(t.g);
|
||||
pb_t.set_h(t.h);
|
||||
pb_t.set_i(t.i);
|
||||
pb_t.set_j(t.j);
|
||||
pb_t.set_k(t.k);
|
||||
pb_t.set_l(t.l);
|
||||
pb_t.set_m(t.m);
|
||||
pb_t.set_n(t.n);
|
||||
pb_t.set_o(t.o);
|
||||
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
TEST_SUITE_END;
|
||||
|
|
@ -1,127 +0,0 @@
|
|||
syntax = "proto3";
|
||||
|
||||
|
||||
message Test1 {
|
||||
int32 a = 1;
|
||||
}
|
||||
message Test2 {
|
||||
string b = 2;
|
||||
}
|
||||
message Test3 {
|
||||
Test1 c = 3;
|
||||
}
|
||||
|
||||
message Test4 {
|
||||
string d = 4;
|
||||
repeated int32 e = 5;
|
||||
}
|
||||
|
||||
message MyTestDouble {
|
||||
double a = 1;
|
||||
double b = 2;
|
||||
double c = 3;
|
||||
}
|
||||
|
||||
message MyTestFloat {
|
||||
float a = 1;
|
||||
float b = 2;
|
||||
float c = 3;
|
||||
float d = 4;
|
||||
float e = 5;
|
||||
}
|
||||
|
||||
message MyTestInt32 {
|
||||
int32 a = 1;
|
||||
repeated int32 b = 2;
|
||||
}
|
||||
message MyTestInt64 {
|
||||
int64 a = 1;
|
||||
repeated int64 b = 2;
|
||||
}
|
||||
message MyTestUint32 {
|
||||
uint32 a = 1;
|
||||
repeated uint32 b = 2;
|
||||
}
|
||||
message MyTestUint64 {
|
||||
uint64 a = 1;
|
||||
repeated uint64 b = 2;
|
||||
}
|
||||
message MyTestEnum {
|
||||
enum Color {
|
||||
Red = 0;
|
||||
Green = 1;
|
||||
Blue = 2;
|
||||
Enum127 = 127;
|
||||
Enum128 = 128;
|
||||
}
|
||||
Color color = 6;
|
||||
}
|
||||
|
||||
message MyTestRepeatedMessage {
|
||||
repeated MyTestFloat fs = 1;
|
||||
}
|
||||
|
||||
message MyTestSint32 {
|
||||
sint32 a = 1;
|
||||
}
|
||||
message MyTestSint64 {
|
||||
sint64 b = 2;
|
||||
}
|
||||
message MyTestMap {
|
||||
map<string, int32> e = 3;
|
||||
}
|
||||
message MyTestFixed32 {
|
||||
fixed32 a = 1;
|
||||
repeated fixed32 b = 2;
|
||||
}
|
||||
message MyTestFixed64 {
|
||||
fixed64 a = 1;
|
||||
repeated fixed64 b = 2;
|
||||
}
|
||||
message MyTestSfixed32 {
|
||||
sfixed32 a = 1;
|
||||
repeated sfixed32 b = 2;
|
||||
}
|
||||
message MyTestSfixed64 {
|
||||
sfixed64 a = 1;
|
||||
repeated sfixed64 b = 2;
|
||||
}
|
||||
|
||||
message MyTestFieldNumberRandom {
|
||||
int32 a = 6;
|
||||
sint64 b = 3;
|
||||
string c = 4;
|
||||
double d = 5;
|
||||
float e = 1;
|
||||
repeated fixed32 f = 128;
|
||||
}
|
||||
|
||||
message MyTestAll {
|
||||
double a = 1;
|
||||
float b = 2;
|
||||
int32 c = 3;
|
||||
int64 d = 4;
|
||||
uint32 e = 5;
|
||||
uint64 f = 6;
|
||||
sint32 g = 7;
|
||||
sint64 h = 8;
|
||||
fixed32 i = 9;
|
||||
fixed64 j = 10;
|
||||
sfixed32 k = 11;
|
||||
sfixed64 l = 12;
|
||||
bool m = 13;
|
||||
string n = 14;
|
||||
bytes o = 15;
|
||||
}
|
||||
message SubMessageForOneof {
|
||||
bool ok = 1;
|
||||
}
|
||||
message SampleMessageOneof {
|
||||
oneof test_oneof {
|
||||
int32 b = 10;
|
||||
int32 a = 8;
|
||||
|
||||
string name = 4;
|
||||
SubMessageForOneof sub_message = 9;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
#include "doctest.h"
|
||||
#include "test_bad_identifiers.struct_pb.h"
|
||||
using namespace doctest;
|
||||
|
||||
TEST_SUITE_BEGIN("test bad identifiers");
|
||||
TEST_CASE("testing conflicting symbol names") {
|
||||
protobuf_unittest::TestConflictingSymbolNames message;
|
||||
message.uint32 = 1;
|
||||
auto sz = struct_pb::internal::get_needed_size(message);
|
||||
CHECK(sz == 3);
|
||||
// Due to different API, the code is useless
|
||||
message.friend_ = 5;
|
||||
CHECK(message.friend_ == 5);
|
||||
message.class_ = 6;
|
||||
CHECK(message.class_ == 6);
|
||||
// NO PROTO3
|
||||
typedef protobuf_unittest::TestConflictingSymbolNamesExtension
|
||||
ExtensionMessage;
|
||||
}
|
||||
TEST_CASE("testing conflicting enum names") {
|
||||
protobuf_unittest::TestConflictingEnumNames message;
|
||||
message.conflicting_enum =
|
||||
protobuf_unittest::TestConflictingEnumNames::while_::and_;
|
||||
CHECK(1 == static_cast<int>(message.conflicting_enum.value()));
|
||||
|
||||
message.conflicting_enum =
|
||||
protobuf_unittest::TestConflictingEnumNames::while_::XOR;
|
||||
CHECK(5 == static_cast<int>(message.conflicting_enum.value()));
|
||||
|
||||
protobuf_unittest::bool_ conflicting_enum;
|
||||
conflicting_enum = protobuf_unittest::bool_::NOT_EQ;
|
||||
CHECK(1 == static_cast<int>(conflicting_enum));
|
||||
|
||||
conflicting_enum = protobuf_unittest::bool_::return_;
|
||||
CHECK(3 == static_cast<int>(conflicting_enum));
|
||||
}
|
||||
TEST_CASE("testing conflicting message names") {
|
||||
protobuf_unittest::NULL_ message;
|
||||
message.int_ = 123;
|
||||
CHECK(message.int_ == 123);
|
||||
}
|
||||
TEST_CASE("testing conflicting extension") {
|
||||
protobuf_unittest::TestConflictingSymbolNames message;
|
||||
// NO_PROTO3
|
||||
}
|
||||
TEST_SUITE_END();
|
||||
|
|
@ -1,335 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Alibaba Group Holding Limited;
|
||||
*
|
||||
* Licensed 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.
|
||||
*/
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "protobuf_sample.hpp"
|
||||
#endif
|
||||
#include "data_def.struct_pb.h"
|
||||
#include "doctest.h"
|
||||
#include "helper.hpp"
|
||||
#include "struct_pb_sample.hpp"
|
||||
using namespace doctest;
|
||||
|
||||
namespace struct_pb_sample {
|
||||
template <typename T>
|
||||
bool check_unique_ptr(const T& lhs, const T& rhs) {
|
||||
if (lhs && rhs) {
|
||||
return *lhs == *rhs;
|
||||
}
|
||||
return !lhs && !rhs;
|
||||
}
|
||||
bool operator==(const Vec3& lhs, const Vec3& rhs) {
|
||||
std::valarray<float> lh({lhs.x, lhs.y, lhs.z});
|
||||
std::valarray<float> rh({rhs.x, rhs.y, rhs.z});
|
||||
return (std::abs(lh - rh) < 0.05f).min();
|
||||
}
|
||||
bool operator==(const Weapon& lhs, const Weapon& rhs) {
|
||||
return lhs.name == rhs.name && lhs.damage == rhs.damage;
|
||||
};
|
||||
bool operator==(const rect32& lhs, const rect32& rhs) {
|
||||
return lhs.x == rhs.x && lhs.y == rhs.y && lhs.width == rhs.width &&
|
||||
lhs.height == rhs.height;
|
||||
}
|
||||
bool operator==(const rect32s& lhs, const rect32s& rhs) {
|
||||
return lhs.rect32_list == rhs.rect32_list;
|
||||
}
|
||||
bool operator==(const person& lhs, const person& rhs) {
|
||||
return lhs.id == rhs.id && lhs.name == rhs.name && lhs.age == rhs.age &&
|
||||
lhs.salary == rhs.salary;
|
||||
}
|
||||
bool operator==(const persons& lhs, const persons& rhs) {
|
||||
return lhs.person_list == rhs.person_list;
|
||||
}
|
||||
bool operator==(const Monster& lhs, const Monster& rhs) {
|
||||
bool ok = check_unique_ptr(lhs.pos, rhs.pos);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
ok = check_unique_ptr(lhs.equipped, rhs.equipped);
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
return lhs.mana == rhs.mana && lhs.hp == rhs.hp && lhs.name == rhs.name &&
|
||||
lhs.inventory == rhs.inventory && lhs.color == rhs.color &&
|
||||
lhs.weapons == rhs.weapons && lhs.path == rhs.path;
|
||||
};
|
||||
bool operator==(const Monsters& lhs, const Monsters& rhs) {
|
||||
return lhs.monsters == rhs.monsters;
|
||||
}
|
||||
|
||||
bool verify(const struct_pb_sample::Weapon& a,
|
||||
const struct_pb_sample::Weapon& b) {
|
||||
assert(a.name == b.name);
|
||||
assert(a.damage == b.damage);
|
||||
return true;
|
||||
}
|
||||
bool verify(const struct_pb_sample::Monster& a,
|
||||
const struct_pb_sample::Monster& b) {
|
||||
assert(a.pos && b.pos);
|
||||
assert(*a.pos == *b.pos);
|
||||
assert(a.mana == b.mana);
|
||||
assert(a.hp == b.hp);
|
||||
assert(a.name == b.name);
|
||||
assert(a.inventory == b.inventory);
|
||||
assert(a.color == b.color);
|
||||
assert(a.weapons.size() == b.weapons.size());
|
||||
for (int i = 0; i < a.weapons.size(); ++i) {
|
||||
auto ok = verify(a.weapons[i], b.weapons[i]);
|
||||
if (!ok) {
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
assert(a.weapons == b.weapons);
|
||||
assert(a.equipped && b.equipped);
|
||||
assert(*a.equipped == *b.equipped);
|
||||
assert(a.path == b.path);
|
||||
return true;
|
||||
}
|
||||
bool verify(const struct_pb_sample::Monsters& a,
|
||||
const struct_pb_sample::Monsters& b) {
|
||||
assert(a.monsters.size() == b.monsters.size());
|
||||
for (int i = 0; i < a.monsters.size(); ++i) {
|
||||
auto ok = verify(a.monsters[i], b.monsters[i]);
|
||||
if (!ok) {
|
||||
return ok;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
template <typename T>
|
||||
T copy(const T& t) {
|
||||
return t;
|
||||
}
|
||||
template <>
|
||||
struct_pb_sample::Monster copy(const struct_pb_sample::Monster& t) {
|
||||
struct_pb_sample::Monster m;
|
||||
m.pos = std::make_unique<struct_pb_sample::Vec3>();
|
||||
*m.pos = *t.pos;
|
||||
m.mana = t.mana;
|
||||
m.hp = t.hp;
|
||||
m.name = t.name;
|
||||
m.inventory = t.inventory;
|
||||
m.color = t.color;
|
||||
m.weapons = t.weapons;
|
||||
m.equipped = std::make_unique<struct_pb_sample::Weapon>();
|
||||
*m.equipped = *t.equipped;
|
||||
m.path = t.path;
|
||||
return m;
|
||||
}
|
||||
template <>
|
||||
struct_pb_sample::Monsters copy(const struct_pb_sample::Monsters& t) {
|
||||
struct_pb_sample::Monsters m;
|
||||
m.monsters.reserve(t.monsters.size());
|
||||
for (const auto& e : t.monsters) {
|
||||
m.monsters.push_back(std::move(copy(e)));
|
||||
}
|
||||
return m;
|
||||
}
|
||||
} // namespace struct_pb_sample
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::rect32s, mygame::rect32s> {
|
||||
bool operator()(const struct_pb_sample::rect32s& t,
|
||||
const mygame::rect32s& pb_t) const {
|
||||
return t.rect32_list == pb_t.rect32_list();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::rect32, mygame::rect32> {
|
||||
bool operator()(const struct_pb_sample::rect32& lhs,
|
||||
const mygame::rect32& rhs) const {
|
||||
return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.width == rhs.width() &&
|
||||
lhs.height == rhs.height();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::Vec3, mygame::Vec3> {
|
||||
bool operator()(const struct_pb_sample::Vec3& lhs,
|
||||
const mygame::Vec3& rhs) const {
|
||||
return lhs.x == rhs.x() && lhs.y == rhs.y() && lhs.z == rhs.z();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::person, mygame::person> {
|
||||
bool operator()(const struct_pb_sample::person& lhs,
|
||||
const mygame::person& rhs) const {
|
||||
return lhs.id == rhs.id() && lhs.name == rhs.name() &&
|
||||
lhs.age == rhs.age() &&
|
||||
std::abs(lhs.salary - rhs.salary()) < 0.0005f;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::persons, mygame::persons> {
|
||||
bool operator()(const struct_pb_sample::persons& lhs,
|
||||
const mygame::persons& rhs) const {
|
||||
return lhs.person_list == rhs.person_list();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::Weapon, mygame::Weapon> {
|
||||
bool operator()(const struct_pb_sample::Weapon& lhs,
|
||||
const mygame::Weapon& rhs) const {
|
||||
return lhs.name == rhs.name() && lhs.damage == rhs.damage();
|
||||
}
|
||||
};
|
||||
bool operator==(const struct_pb_sample::Monster::Color& a,
|
||||
const mygame::Monster::Color& b) {
|
||||
return int(a) == int(b);
|
||||
}
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::Monster, mygame::Monster> {
|
||||
bool operator()(const struct_pb_sample::Monster& lhs,
|
||||
const mygame::Monster& rhs) const {
|
||||
auto ok = (lhs.name == rhs.name() && lhs.mana == rhs.mana() &&
|
||||
lhs.hp == rhs.hp() && lhs.inventory == rhs.inventory() &&
|
||||
lhs.color == rhs.color() && lhs.weapons == rhs.weapons() &&
|
||||
lhs.path == rhs.path());
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
if (lhs.pos && rhs.has_pos()) {
|
||||
ok =
|
||||
PB_equal<struct_pb_sample::Vec3, mygame::Vec3>()(*lhs.pos, rhs.pos());
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs.pos || rhs.has_pos()) {
|
||||
return false;
|
||||
}
|
||||
if (lhs.equipped && rhs.has_equipped()) {
|
||||
ok = PB_equal<struct_pb_sample::Weapon, mygame::Weapon>()(*lhs.equipped,
|
||||
rhs.equipped());
|
||||
if (!ok) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (lhs.equipped || rhs.has_equipped()) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<struct_pb_sample::Monsters, mygame::Monsters> {
|
||||
bool operator()(const struct_pb_sample::Monsters& lhs,
|
||||
const mygame::Monsters& rhs) const {
|
||||
return lhs.monsters == rhs.monsters();
|
||||
}
|
||||
};
|
||||
template <typename T, typename U>
|
||||
void check_repeated(const std::vector<T>& a,
|
||||
const google::protobuf::RepeatedPtrField<U>& b) {
|
||||
bool ret = (a == b);
|
||||
REQUIRE(ret);
|
||||
}
|
||||
#endif
|
||||
|
||||
TEST_SUITE_BEGIN("test pb benchmark struct");
|
||||
TEST_CASE("testing rect") {
|
||||
auto my_rects = struct_pb_sample::create_rects(OBJECT_COUNT);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_rects = protobuf_sample::create_rects(OBJECT_COUNT);
|
||||
#endif
|
||||
for (int i = 0; i < OBJECT_COUNT; ++i) {
|
||||
auto my_rect = my_rects.rect32_list[i];
|
||||
check_self(my_rect);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_rect = *(pb_rects.rect32_list().begin() + i);
|
||||
REQUIRE(my_rect.x == pb_rect.x());
|
||||
REQUIRE(my_rect.y == pb_rect.y());
|
||||
REQUIRE(my_rect.width == pb_rect.width());
|
||||
REQUIRE(my_rect.height == pb_rect.height());
|
||||
check_with_protobuf(my_rect, pb_rect);
|
||||
#endif
|
||||
}
|
||||
check_self(my_rects);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(my_rects, pb_rects);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("testing person") {
|
||||
auto my_persons = struct_pb_sample::create_persons(OBJECT_COUNT);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_persons = protobuf_sample::create_persons(OBJECT_COUNT);
|
||||
#endif
|
||||
for (int i = 0; i < OBJECT_COUNT; ++i) {
|
||||
auto my_person = my_persons.person_list[i];
|
||||
check_self(my_person);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_person = *(pb_persons.person_list().begin() + i);
|
||||
REQUIRE(my_person.id == pb_person.id());
|
||||
REQUIRE(my_person.name == pb_person.name());
|
||||
REQUIRE(my_person.age == pb_person.age());
|
||||
REQUIRE(my_person.salary == pb_person.salary());
|
||||
check_with_protobuf(my_person, pb_person);
|
||||
#endif
|
||||
}
|
||||
check_self(my_persons);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(my_persons, pb_persons);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("testing monsters") {
|
||||
using namespace struct_pb_sample;
|
||||
auto my_ms = struct_pb_sample::create_monsters(OBJECT_COUNT);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_ms = protobuf_sample::create_monsters(OBJECT_COUNT);
|
||||
#endif
|
||||
for (int i = 0; i < OBJECT_COUNT; ++i) {
|
||||
auto& my_m = my_ms.monsters[i];
|
||||
check_self(my_m);
|
||||
|
||||
#ifdef HAVE_PROTOBUF
|
||||
auto pb_m = *(pb_ms.monsters().begin() + i);
|
||||
REQUIRE(my_m.pos);
|
||||
REQUIRE(my_m.mana == pb_m.mana());
|
||||
REQUIRE(my_m.hp == pb_m.hp());
|
||||
REQUIRE(my_m.name == pb_m.name());
|
||||
REQUIRE(my_m.inventory == pb_m.inventory());
|
||||
REQUIRE(my_m.color == pb_m.color());
|
||||
check_repeated(my_m.weapons, pb_m.weapons());
|
||||
check_repeated(my_m.path, pb_m.path());
|
||||
|
||||
check_with_protobuf(my_m, pb_m);
|
||||
#endif
|
||||
|
||||
std::string my_buf = struct_pb::serialize<std::string>(my_m);
|
||||
struct_pb_sample::Monster d_t{};
|
||||
auto ok = struct_pb::deserialize_to(d_t, my_buf);
|
||||
REQUIRE(ok);
|
||||
CHECK(struct_pb_sample::verify(d_t, my_m));
|
||||
REQUIRE(d_t.pos);
|
||||
REQUIRE(my_m.pos);
|
||||
CHECK(*d_t.pos == *my_m.pos);
|
||||
CHECK(d_t.mana == my_m.mana);
|
||||
CHECK(d_t.hp == my_m.hp);
|
||||
CHECK(d_t.name == my_m.name);
|
||||
CHECK(d_t.inventory == my_m.inventory);
|
||||
CHECK(d_t.color == my_m.color);
|
||||
REQUIRE(d_t.equipped);
|
||||
REQUIRE(my_m.equipped);
|
||||
CHECK(*d_t.equipped == *my_m.equipped);
|
||||
CHECK(d_t.path == my_m.path);
|
||||
}
|
||||
check_self(my_ms);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
check_with_protobuf(my_ms, pb_ms);
|
||||
#endif
|
||||
}
|
||||
TEST_SUITE_END;
|
||||
|
|
@ -1,108 +0,0 @@
|
|||
#include "doctest.h"
|
||||
#include "helper.hpp"
|
||||
#ifdef HAVE_PROTOBUF
|
||||
#include "test_pb.pb.h"
|
||||
#endif
|
||||
using namespace doctest;
|
||||
#ifdef HAVE_PROTOBUF
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::SubMessageForOneof, SubMessageForOneof> {
|
||||
bool operator()(const test_struct_pb::SubMessageForOneof& t,
|
||||
const SubMessageForOneof& pb_t) const {
|
||||
return t.ok == pb_t.ok();
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct PB_equal<test_struct_pb::SampleMessageOneof, SampleMessageOneof> {
|
||||
bool operator()(const test_struct_pb::SampleMessageOneof& t,
|
||||
const SampleMessageOneof& pb_t) const {
|
||||
if (int(t.test_oneof_case()) != int(pb_t.test_oneof_case())) {
|
||||
return false;
|
||||
}
|
||||
switch (pb_t.test_oneof_case()) {
|
||||
case SampleMessageOneof::kB: {
|
||||
return t.b() == pb_t.b();
|
||||
} break;
|
||||
case SampleMessageOneof::kA: {
|
||||
return t.a() == pb_t.a();
|
||||
} break;
|
||||
case SampleMessageOneof::kName: {
|
||||
return t.name() == pb_t.name();
|
||||
} break;
|
||||
case SampleMessageOneof::kSubMessage: {
|
||||
return PB_equal<test_struct_pb::SubMessageForOneof,
|
||||
SubMessageForOneof>()(*t.sub_message(),
|
||||
pb_t.sub_message());
|
||||
} break;
|
||||
case SampleMessageOneof::TEST_ONEOF_NOT_SET:
|
||||
break;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
};
|
||||
#endif
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct equal_to<test_struct_pb::SampleMessageOneof> {
|
||||
bool operator()(const test_struct_pb::SampleMessageOneof& lhs,
|
||||
const test_struct_pb::SampleMessageOneof& rhs) const {
|
||||
if (lhs.test_oneof_case() != rhs.test_oneof_case()) {
|
||||
return false;
|
||||
}
|
||||
if (lhs.has_sub_message() && rhs.has_sub_message()) {
|
||||
return equal_to<test_struct_pb::SubMessageForOneof>()(*lhs.sub_message(),
|
||||
*rhs.sub_message());
|
||||
}
|
||||
return lhs.test_oneof == rhs.test_oneof;
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
TEST_CASE("testing oneof, b") {
|
||||
test_struct_pb::SampleMessageOneof t;
|
||||
int b = 13298;
|
||||
t.set_b(b);
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
SampleMessageOneof pb_t;
|
||||
pb_t.set_b(b);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
TEST_CASE("testing oneof, a") {
|
||||
test_struct_pb::SampleMessageOneof t;
|
||||
int a = 66613298;
|
||||
t.set_a(a);
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
SampleMessageOneof pb_t;
|
||||
pb_t.set_a(a);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
TEST_CASE("testing oneof, name") {
|
||||
std::string name = "oneof, name";
|
||||
test_struct_pb::SampleMessageOneof t;
|
||||
t.set_name(name);
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
SampleMessageOneof pb_t;
|
||||
pb_t.set_name(name);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_CASE("testing oneof, submessage") {
|
||||
test_struct_pb::SampleMessageOneof t;
|
||||
auto sub = new test_struct_pb::SubMessageForOneof{true};
|
||||
t.set_allocated_sub_message(sub);
|
||||
check_self(t);
|
||||
#ifdef HAVE_PROTOBUF
|
||||
SampleMessageOneof pb_t;
|
||||
auto m = new SubMessageForOneof();
|
||||
m->set_ok(true);
|
||||
pb_t.set_allocated_sub_message(m);
|
||||
check_with_protobuf(t, pb_t);
|
||||
#endif
|
||||
}
|
||||
|
|
@ -0,0 +1,688 @@
|
|||
#pragma once
|
||||
|
||||
#include <ylt/struct_pb.hpp>
|
||||
#if defined(STRUCT_PB_WITH_PROTO)
|
||||
#include "data_def.pb.h"
|
||||
#include "unittest_proto3.pb.h"
|
||||
#endif
|
||||
|
||||
#define PUBLIC(T) : public iguana::base_impl<T>
|
||||
|
||||
// define the struct as msg in proto
|
||||
namespace stpb {
|
||||
enum class Enum {
|
||||
ZERO = 0,
|
||||
FOO = 1,
|
||||
BAR = 2,
|
||||
BAZ = 123456,
|
||||
NEG = -1, // Intentionally negative.
|
||||
};
|
||||
|
||||
struct BaseTypeMsg PUBLIC(BaseTypeMsg) {
|
||||
BaseTypeMsg() = default;
|
||||
BaseTypeMsg(int32_t a, int64_t b, uint32_t c, uint64_t d, float e, double f,
|
||||
bool g, std::string h, Enum i)
|
||||
: optional_int32(a),
|
||||
optional_int64(b),
|
||||
optional_uint32(c),
|
||||
optional_uint64(d),
|
||||
optional_float(e),
|
||||
optional_double(f),
|
||||
optional_bool(g),
|
||||
optional_string(std::move(h)),
|
||||
optional_enum(i) {}
|
||||
int32_t optional_int32;
|
||||
int64_t optional_int64;
|
||||
uint32_t optional_uint32;
|
||||
uint64_t optional_uint64;
|
||||
float optional_float;
|
||||
double optional_double;
|
||||
bool optional_bool;
|
||||
std::string optional_string;
|
||||
Enum optional_enum;
|
||||
bool operator==(const BaseTypeMsg& other) const {
|
||||
return optional_int32 == other.optional_int32 &&
|
||||
optional_int64 == other.optional_int64 &&
|
||||
optional_uint32 == other.optional_uint32 &&
|
||||
optional_uint64 == other.optional_uint64 &&
|
||||
optional_float == other.optional_float &&
|
||||
optional_double == other.optional_double &&
|
||||
optional_bool == other.optional_bool &&
|
||||
optional_string == other.optional_string &&
|
||||
optional_enum == other.optional_enum;
|
||||
}
|
||||
};
|
||||
REFLECTION(BaseTypeMsg, optional_int32, optional_int64, optional_uint32,
|
||||
optional_uint64, optional_float, optional_double, optional_bool,
|
||||
optional_string, optional_enum);
|
||||
|
||||
struct IguanaTypeMsg PUBLIC(IguanaTypeMsg) {
|
||||
IguanaTypeMsg() = default;
|
||||
IguanaTypeMsg(iguana::sint32_t a, iguana::sint64_t b, iguana::fixed32_t c,
|
||||
iguana::fixed64_t d = {}, iguana::sfixed32_t e = {},
|
||||
iguana::sfixed64_t f = {})
|
||||
: optional_sint32(a),
|
||||
optional_sint64(b),
|
||||
optional_fixed32(c),
|
||||
optional_fixed64(d),
|
||||
optional_sfixed32(e),
|
||||
optional_sfixed64(f) {}
|
||||
iguana::sint32_t optional_sint32;
|
||||
iguana::sint64_t optional_sint64;
|
||||
iguana::fixed32_t optional_fixed32;
|
||||
iguana::fixed64_t optional_fixed64;
|
||||
iguana::sfixed32_t optional_sfixed32;
|
||||
iguana::sfixed64_t optional_sfixed64;
|
||||
|
||||
bool operator==(const IguanaTypeMsg& other) const {
|
||||
return optional_sint32 == other.optional_sint32 &&
|
||||
optional_sint64 == other.optional_sint64 &&
|
||||
optional_fixed32 == other.optional_fixed32 &&
|
||||
optional_fixed64 == other.optional_fixed64 &&
|
||||
optional_sfixed32 == other.optional_sfixed32 &&
|
||||
optional_sfixed64 == other.optional_sfixed64;
|
||||
}
|
||||
};
|
||||
REFLECTION(IguanaTypeMsg, optional_sint32, optional_sint64, optional_fixed32,
|
||||
optional_fixed64, optional_sfixed32, optional_sfixed64);
|
||||
|
||||
struct RepeatBaseTypeMsg PUBLIC(RepeatBaseTypeMsg) {
|
||||
RepeatBaseTypeMsg() = default;
|
||||
RepeatBaseTypeMsg(std::vector<uint32_t> a, std::vector<uint64_t> b,
|
||||
std::vector<int32_t> c, std::vector<int64_t> d,
|
||||
std::vector<float> e, std::vector<double> f,
|
||||
std::vector<std::string> g, std::vector<Enum> h)
|
||||
: repeated_uint32(std::move(a)),
|
||||
repeated_uint64(std::move(b)),
|
||||
repeated_int32(std::move(c)),
|
||||
repeated_int64(std::move(d)),
|
||||
repeated_float(std::move(e)),
|
||||
repeated_double(std::move(f)),
|
||||
repeated_string(std::move(g)),
|
||||
repeated_enum(std::move(h)) {}
|
||||
std::vector<uint32_t> repeated_uint32;
|
||||
std::vector<uint64_t> repeated_uint64;
|
||||
std::vector<int32_t> repeated_int32;
|
||||
std::vector<int64_t> repeated_int64;
|
||||
std::vector<float> repeated_float;
|
||||
std::vector<double> repeated_double;
|
||||
std::vector<std::string> repeated_string;
|
||||
std::vector<Enum> repeated_enum;
|
||||
};
|
||||
|
||||
REFLECTION(RepeatBaseTypeMsg, repeated_uint32, repeated_uint64, repeated_int32,
|
||||
repeated_int64, repeated_float, repeated_double, repeated_string,
|
||||
repeated_enum);
|
||||
|
||||
struct RepeatIguanaTypeMsg PUBLIC(RepeatIguanaTypeMsg) {
|
||||
RepeatIguanaTypeMsg() = default;
|
||||
RepeatIguanaTypeMsg(std::vector<iguana::sfixed32_t> a,
|
||||
std::vector<iguana::sfixed64_t> b,
|
||||
std::vector<iguana::fixed32_t> c,
|
||||
std::vector<iguana::fixed64_t> d,
|
||||
std::vector<iguana::sfixed32_t> e,
|
||||
std::vector<iguana::sfixed64_t> f)
|
||||
: repeated_sint32(std::move(a)),
|
||||
repeated_sint64(std::move(b)),
|
||||
repeated_fixed32(std::move(c)),
|
||||
repeated_fixed64(std::move(d)),
|
||||
repeated_sfixed32(std::move(e)),
|
||||
repeated_sfixed64(std::move(f)) {}
|
||||
std::vector<iguana::sfixed32_t> repeated_sint32;
|
||||
std::vector<iguana::sfixed64_t> repeated_sint64;
|
||||
std::vector<iguana::fixed32_t> repeated_fixed32;
|
||||
std::vector<iguana::fixed64_t> repeated_fixed64;
|
||||
std::vector<iguana::sfixed32_t> repeated_sfixed32;
|
||||
std::vector<iguana::sfixed64_t> repeated_sfixed64;
|
||||
};
|
||||
|
||||
REFLECTION(RepeatIguanaTypeMsg, repeated_sint32, repeated_sint64,
|
||||
repeated_fixed32, repeated_fixed64, repeated_sfixed32,
|
||||
repeated_sfixed64);
|
||||
|
||||
struct NestedMsg PUBLIC(NestedMsg) {
|
||||
NestedMsg() = default;
|
||||
NestedMsg(BaseTypeMsg a, std::vector<BaseTypeMsg> b, IguanaTypeMsg c,
|
||||
std::vector<IguanaTypeMsg> d, std::vector<RepeatBaseTypeMsg> e)
|
||||
: base_msg(std::move(a)),
|
||||
repeat_base_msg(std::move(b)),
|
||||
iguana_type_msg(std::move(c)),
|
||||
repeat_iguna_msg(std::move(d)),
|
||||
repeat_repeat_base_msg(std::move(e)) {}
|
||||
BaseTypeMsg base_msg;
|
||||
std::vector<BaseTypeMsg> repeat_base_msg;
|
||||
IguanaTypeMsg iguana_type_msg;
|
||||
std::vector<IguanaTypeMsg> repeat_iguna_msg;
|
||||
std::vector<RepeatBaseTypeMsg> repeat_repeat_base_msg;
|
||||
};
|
||||
REFLECTION(NestedMsg, base_msg, repeat_base_msg, iguana_type_msg,
|
||||
repeat_iguna_msg, repeat_repeat_base_msg);
|
||||
|
||||
struct MapMsg PUBLIC(MapMsg) {
|
||||
MapMsg() = default;
|
||||
MapMsg(std::unordered_map<iguana::sfixed64_t, std::string> a,
|
||||
std::unordered_map<std::string, IguanaTypeMsg> b,
|
||||
std::map<int, RepeatBaseTypeMsg> c)
|
||||
: sfix64_str_map(std::move(a)),
|
||||
str_iguana_type_msg_map(std::move(b)),
|
||||
int_repeat_base_msg_map(std::move(c)) {}
|
||||
std::unordered_map<iguana::sfixed64_t, std::string> sfix64_str_map{};
|
||||
std::unordered_map<std::string, IguanaTypeMsg> str_iguana_type_msg_map{};
|
||||
std::map<int, RepeatBaseTypeMsg> int_repeat_base_msg_map{};
|
||||
};
|
||||
REFLECTION(MapMsg, sfix64_str_map, str_iguana_type_msg_map,
|
||||
int_repeat_base_msg_map);
|
||||
|
||||
struct BaseOneofMsg PUBLIC(BaseOneofMsg) {
|
||||
BaseOneofMsg() = default;
|
||||
BaseOneofMsg(int32_t a, std::variant<double, std::string, BaseTypeMsg> b,
|
||||
double c)
|
||||
: optional_int32(a), one_of(std::move(b)), optional_double(c) {}
|
||||
int32_t optional_int32;
|
||||
std::variant<double, std::string, BaseTypeMsg> one_of;
|
||||
double optional_double;
|
||||
};
|
||||
REFLECTION(BaseOneofMsg, optional_int32, one_of, optional_double);
|
||||
|
||||
struct NestOneofMsg PUBLIC(NestOneofMsg) {
|
||||
NestOneofMsg() = default;
|
||||
NestOneofMsg(std::variant<std::string, BaseOneofMsg> a)
|
||||
: nest_one_of_msg(std::move(a)) {}
|
||||
std::variant<std::string, BaseOneofMsg> nest_one_of_msg;
|
||||
};
|
||||
REFLECTION(NestOneofMsg, nest_one_of_msg);
|
||||
|
||||
struct simple_t PUBLIC(simple_t) {
|
||||
simple_t() = default;
|
||||
simple_t(int32_t x, int32_t y, int64_t z, int64_t w, std::string s)
|
||||
: a(x), b(y), c(z), d(w), str(std::move(s)) {}
|
||||
int32_t a;
|
||||
int32_t b;
|
||||
int64_t c;
|
||||
int64_t d;
|
||||
std::string str;
|
||||
};
|
||||
REFLECTION(simple_t, a, b, c, d, str);
|
||||
|
||||
struct simple_t1 PUBLIC(simple_t1) {
|
||||
simple_t1() = default;
|
||||
simple_t1(int32_t x, int32_t y, int64_t z, int64_t w, std::string_view s)
|
||||
: a(x), b(y), c(z), d(w), str(s) {}
|
||||
int32_t a;
|
||||
int32_t b;
|
||||
int64_t c;
|
||||
int64_t d;
|
||||
std::string_view str;
|
||||
};
|
||||
REFLECTION(simple_t1, a, b, c, d, str);
|
||||
|
||||
enum Color : uint8_t { Red, Green, Blue };
|
||||
|
||||
struct simple_t2 PUBLIC(simple_t2) {
|
||||
simple_t2() = default;
|
||||
simple_t2(int16_t x, uint8_t y, Color z, int64_t w, std::string_view s = "")
|
||||
: a(x), b(y), c(z), d(w), str(s) {}
|
||||
int16_t a;
|
||||
uint8_t b;
|
||||
Color c;
|
||||
int64_t d;
|
||||
std::string_view str;
|
||||
};
|
||||
REFLECTION(simple_t2, a, b, c, d, str);
|
||||
|
||||
struct person {
|
||||
person() = default;
|
||||
person(int32_t a, std::string b, int c, double d)
|
||||
: id(a), name(std::move(b)), age(c), salary(d) {}
|
||||
int32_t id;
|
||||
std::string name;
|
||||
int age;
|
||||
double salary;
|
||||
};
|
||||
REFLECTION(person, id, name, age, salary);
|
||||
|
||||
struct rect PUBLIC(rect) {
|
||||
rect() = default;
|
||||
rect(int32_t a, int32_t b, int32_t c, int32_t d)
|
||||
: x(a), y(b), width(c), height(d) {}
|
||||
int32_t x = 1;
|
||||
int32_t y = 0;
|
||||
int32_t width = 11;
|
||||
int32_t height = 1;
|
||||
};
|
||||
REFLECTION(rect, x, y, width, height);
|
||||
|
||||
struct Vec3 PUBLIC(Vec3) {
|
||||
Vec3() = default;
|
||||
Vec3(float a, float b, float c) : x(a), y(b), z(c) {}
|
||||
float x;
|
||||
float y;
|
||||
float z;
|
||||
|
||||
REFLECTION(Vec3, x, y, z);
|
||||
};
|
||||
|
||||
struct Weapon PUBLIC(Weapon) {
|
||||
Weapon() = default;
|
||||
Weapon(std::string a, int32_t b) : name(std::move(a)), damage(b) {}
|
||||
std::string name;
|
||||
int32_t damage;
|
||||
};
|
||||
REFLECTION(Weapon, name, damage);
|
||||
|
||||
struct Monster PUBLIC(Monster) {
|
||||
Monster() = default;
|
||||
Monster(Vec3 a, int32_t b, int32_t c, std::string d, std::string e, int32_t f,
|
||||
std::vector<Weapon> g, Weapon h, std::vector<Vec3> i)
|
||||
: pos(a),
|
||||
mana(b),
|
||||
hp(c),
|
||||
name(std::move(d)),
|
||||
inventory(std::move(e)),
|
||||
color(f),
|
||||
weapons(std::move(g)),
|
||||
equipped(std::move(h)),
|
||||
path(std::move(i)) {}
|
||||
Vec3 pos;
|
||||
int32_t mana;
|
||||
int32_t hp;
|
||||
std::string name;
|
||||
std::string inventory;
|
||||
int32_t color;
|
||||
std::vector<Weapon> weapons;
|
||||
Weapon equipped;
|
||||
std::vector<Vec3> path;
|
||||
};
|
||||
REFLECTION(Monster, pos, mana, hp, name, inventory, color, weapons, equipped,
|
||||
path);
|
||||
|
||||
struct bench_int32 PUBLIC(bench_int32) {
|
||||
bench_int32() = default;
|
||||
bench_int32(int32_t x, int32_t y, int32_t z, int32_t u)
|
||||
: a(x), b(y), c(z), d(u) {}
|
||||
int32_t a;
|
||||
int32_t b;
|
||||
int32_t c;
|
||||
int32_t d;
|
||||
};
|
||||
REFLECTION(bench_int32, a, b, c, d);
|
||||
|
||||
} // namespace stpb
|
||||
|
||||
inline auto create_person() {
|
||||
stpb::person p{432798, std::string(1024, 'A'), 24, 65536.42};
|
||||
return p;
|
||||
}
|
||||
|
||||
inline stpb::Monster create_sp_monster() {
|
||||
stpb::Monster m = {
|
||||
{1, 2, 3},
|
||||
16,
|
||||
24,
|
||||
"it is a test",
|
||||
"\1\2\3\4",
|
||||
stpb::Color::Red,
|
||||
{{"gun", 42}, {"shotgun", 56}},
|
||||
{"air craft", 67},
|
||||
{{7, 8, 9}, {71, 81, 91}},
|
||||
};
|
||||
return m;
|
||||
}
|
||||
|
||||
#if defined(STRUCT_PB_WITH_PROTO)
|
||||
namespace protobuf_sample {
|
||||
inline mygame::person create_person() {
|
||||
mygame::person p;
|
||||
p.set_id(432798);
|
||||
p.set_name(std::string(1024, 'A'));
|
||||
p.set_age(24);
|
||||
p.set_salary(65536.42);
|
||||
return p;
|
||||
}
|
||||
|
||||
inline mygame::Monster create_monster() {
|
||||
mygame::Monster m;
|
||||
|
||||
auto vec = new mygame::Vec3;
|
||||
vec->set_x(1);
|
||||
vec->set_y(2);
|
||||
vec->set_z(3);
|
||||
m.set_allocated_pos(vec);
|
||||
m.set_mana(16);
|
||||
m.set_hp(24);
|
||||
m.set_name("it is a test");
|
||||
m.set_inventory("\1\2\3\4");
|
||||
m.set_color(::mygame::Monster_Color::Monster_Color_Red);
|
||||
auto w1 = m.add_weapons();
|
||||
w1->set_name("gun");
|
||||
w1->set_damage(42);
|
||||
auto w2 = m.add_weapons();
|
||||
w2->set_name("shotgun");
|
||||
w2->set_damage(56);
|
||||
auto w3 = new mygame::Weapon;
|
||||
w3->set_name("air craft");
|
||||
w3->set_damage(67);
|
||||
m.set_allocated_equipped(w3);
|
||||
auto p1 = m.add_path();
|
||||
p1->set_x(7);
|
||||
p1->set_y(8);
|
||||
p1->set_z(9);
|
||||
auto p2 = m.add_path();
|
||||
p2->set_x(71);
|
||||
p2->set_y(81);
|
||||
p2->set_z(91);
|
||||
|
||||
return m;
|
||||
}
|
||||
} // namespace protobuf_sample
|
||||
|
||||
void SetBaseTypeMsg(const stpb::BaseTypeMsg& st, pb::BaseTypeMsg& msg) {
|
||||
msg.set_optional_int32(st.optional_int32);
|
||||
msg.set_optional_int64(st.optional_int64);
|
||||
msg.set_optional_uint32(st.optional_uint32);
|
||||
msg.set_optional_uint64(st.optional_uint64);
|
||||
msg.set_optional_float(st.optional_float);
|
||||
msg.set_optional_double(st.optional_double);
|
||||
msg.set_optional_bool(st.optional_bool);
|
||||
msg.set_optional_string(st.optional_string);
|
||||
msg.set_optional_enum(static_cast<pb::Enum>(st.optional_enum));
|
||||
}
|
||||
|
||||
void CheckBaseTypeMsg(const stpb::BaseTypeMsg& st, const pb::BaseTypeMsg& msg) {
|
||||
CHECK(st.optional_int32 == msg.optional_int32());
|
||||
CHECK(st.optional_int64 == msg.optional_int64());
|
||||
CHECK(st.optional_uint32 == msg.optional_uint32());
|
||||
CHECK(st.optional_uint64 == msg.optional_uint64());
|
||||
CHECK(st.optional_float == msg.optional_float());
|
||||
CHECK(st.optional_double == msg.optional_double());
|
||||
CHECK(st.optional_bool == msg.optional_bool());
|
||||
CHECK(st.optional_string == msg.optional_string());
|
||||
CHECK(static_cast<int32_t>(st.optional_enum) ==
|
||||
static_cast<int32_t>(msg.optional_enum()));
|
||||
}
|
||||
|
||||
void SetIguanaTypeMsg(const stpb::IguanaTypeMsg& st, pb::IguanaTypeMsg& msg) {
|
||||
msg.set_optional_sint32(st.optional_sint32.val);
|
||||
msg.set_optional_sint64(st.optional_sint64.val);
|
||||
msg.set_optional_fixed32(st.optional_fixed32.val);
|
||||
msg.set_optional_fixed64(st.optional_fixed64.val);
|
||||
msg.set_optional_sfixed32(st.optional_sfixed32.val);
|
||||
msg.set_optional_sfixed64(st.optional_sfixed64.val);
|
||||
}
|
||||
|
||||
void CheckIguanaTypeMsg(const stpb::IguanaTypeMsg& st,
|
||||
const pb::IguanaTypeMsg& msg) {
|
||||
CHECK(st.optional_sint32.val == msg.optional_sint32());
|
||||
CHECK(st.optional_sint64.val == msg.optional_sint64());
|
||||
CHECK(st.optional_fixed32.val == msg.optional_fixed32());
|
||||
CHECK(st.optional_fixed64.val == msg.optional_fixed64());
|
||||
CHECK(st.optional_sfixed32.val == msg.optional_sfixed32());
|
||||
CHECK(st.optional_sfixed64.val == msg.optional_sfixed64());
|
||||
}
|
||||
|
||||
void SetRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st,
|
||||
pb::RepeatBaseTypeMsg& msg) {
|
||||
for (auto v : st.repeated_uint32) {
|
||||
msg.add_repeated_uint32(v);
|
||||
}
|
||||
for (auto v : st.repeated_uint64) {
|
||||
msg.add_repeated_uint64(v);
|
||||
}
|
||||
for (auto v : st.repeated_int32) {
|
||||
msg.add_repeated_int32(v);
|
||||
}
|
||||
for (auto v : st.repeated_int64) {
|
||||
msg.add_repeated_int64(v);
|
||||
}
|
||||
for (auto v : st.repeated_float) {
|
||||
msg.add_repeated_float(v);
|
||||
}
|
||||
for (auto v : st.repeated_double) {
|
||||
msg.add_repeated_double(v);
|
||||
}
|
||||
for (auto v : st.repeated_string) {
|
||||
msg.add_repeated_string(v);
|
||||
}
|
||||
for (auto v : st.repeated_enum) {
|
||||
msg.add_repeated_enum(static_cast<pb::Enum>(v));
|
||||
}
|
||||
}
|
||||
|
||||
void CheckRepeatBaseTypeMsg(const stpb::RepeatBaseTypeMsg& st,
|
||||
const pb::RepeatBaseTypeMsg& msg) {
|
||||
for (size_t i = 0; i < st.repeated_uint32.size(); ++i) {
|
||||
CHECK(st.repeated_uint32[i] == msg.repeated_uint32(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_uint64.size(); ++i) {
|
||||
CHECK(st.repeated_uint64[i] == msg.repeated_uint64(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_int32.size(); ++i) {
|
||||
CHECK(st.repeated_int32[i] == msg.repeated_int32(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_int64.size(); ++i) {
|
||||
CHECK(st.repeated_int64[i] == msg.repeated_int64(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_float.size(); ++i) {
|
||||
CHECK(st.repeated_float[i] == msg.repeated_float(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_double.size(); ++i) {
|
||||
CHECK(st.repeated_double[i] == msg.repeated_double(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_string.size(); ++i) {
|
||||
CHECK(st.repeated_string[i] == msg.repeated_string(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_enum.size(); ++i) {
|
||||
CHECK(static_cast<int>(st.repeated_enum[i]) ==
|
||||
static_cast<int>(msg.repeated_enum(i)));
|
||||
}
|
||||
}
|
||||
|
||||
void SetRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st,
|
||||
pb::RepeatIguanaTypeMsg& msg) {
|
||||
for (auto v : st.repeated_sint32) {
|
||||
msg.add_repeated_sint32(v.val);
|
||||
}
|
||||
for (auto v : st.repeated_sint64) {
|
||||
msg.add_repeated_sint64(v.val);
|
||||
}
|
||||
for (auto v : st.repeated_fixed32) {
|
||||
msg.add_repeated_fixed32(v.val);
|
||||
}
|
||||
for (auto v : st.repeated_fixed64) {
|
||||
msg.add_repeated_fixed64(v.val);
|
||||
}
|
||||
for (auto v : st.repeated_sfixed32) {
|
||||
msg.add_repeated_sfixed32(v.val);
|
||||
}
|
||||
for (auto v : st.repeated_sfixed64) {
|
||||
msg.add_repeated_sfixed64(v.val);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckRepeatIguanaTypeMsg(const stpb::RepeatIguanaTypeMsg& st,
|
||||
const pb::RepeatIguanaTypeMsg& msg) {
|
||||
for (size_t i = 0; i < st.repeated_sint32.size(); ++i) {
|
||||
CHECK(st.repeated_sint32[i].val == msg.repeated_sint32(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_sint64.size(); ++i) {
|
||||
CHECK(st.repeated_sint64[i].val == msg.repeated_sint64(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_fixed32.size(); ++i) {
|
||||
CHECK(st.repeated_fixed32[i].val == msg.repeated_fixed32(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_fixed64.size(); ++i) {
|
||||
CHECK(st.repeated_fixed64[i].val == msg.repeated_fixed64(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_sfixed32.size(); ++i) {
|
||||
CHECK(st.repeated_sfixed32[i].val == msg.repeated_sfixed32(i));
|
||||
}
|
||||
for (size_t i = 0; i < st.repeated_sfixed64.size(); ++i) {
|
||||
CHECK(st.repeated_sfixed64[i].val == msg.repeated_sfixed64(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SetNestedMsg(const stpb::NestedMsg& st, pb::NestedMsg& msg) {
|
||||
SetBaseTypeMsg(st.base_msg, *msg.mutable_base_msg());
|
||||
|
||||
for (const auto& base_msg : st.repeat_base_msg) {
|
||||
auto* base_msg_ptr = msg.add_repeat_base_msg();
|
||||
SetBaseTypeMsg(base_msg, *base_msg_ptr);
|
||||
}
|
||||
|
||||
SetIguanaTypeMsg(st.iguana_type_msg, *msg.mutable_iguana_type_msg());
|
||||
|
||||
for (const auto& iguana_type_msg : st.repeat_iguna_msg) {
|
||||
auto* iguana_type_msg_ptr = msg.add_repeat_iguna_msg();
|
||||
SetIguanaTypeMsg(iguana_type_msg, *iguana_type_msg_ptr);
|
||||
}
|
||||
|
||||
for (const auto& repeat_base_msg : st.repeat_repeat_base_msg) {
|
||||
auto* repeat_base_msg_ptr = msg.add_repeat_repeat_base_msg();
|
||||
SetRepeatBaseTypeMsg(repeat_base_msg, *repeat_base_msg_ptr);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckNestedMsg(const stpb::NestedMsg& st, const pb::NestedMsg& msg) {
|
||||
CheckBaseTypeMsg(st.base_msg, msg.base_msg());
|
||||
|
||||
CHECK(st.repeat_base_msg.size() == msg.repeat_base_msg_size());
|
||||
for (size_t i = 0; i < st.repeat_base_msg.size(); ++i) {
|
||||
CheckBaseTypeMsg(st.repeat_base_msg[i], msg.repeat_base_msg(i));
|
||||
}
|
||||
|
||||
CheckIguanaTypeMsg(st.iguana_type_msg, msg.iguana_type_msg());
|
||||
|
||||
CHECK(st.repeat_iguna_msg.size() == msg.repeat_iguna_msg_size());
|
||||
for (size_t i = 0; i < st.repeat_iguna_msg.size(); ++i) {
|
||||
CheckIguanaTypeMsg(st.repeat_iguna_msg[i], msg.repeat_iguna_msg(i));
|
||||
}
|
||||
|
||||
CHECK(st.repeat_repeat_base_msg.size() == msg.repeat_repeat_base_msg_size());
|
||||
for (size_t i = 0; i < st.repeat_repeat_base_msg.size(); ++i) {
|
||||
CheckRepeatBaseTypeMsg(st.repeat_repeat_base_msg[i],
|
||||
msg.repeat_repeat_base_msg(i));
|
||||
}
|
||||
}
|
||||
|
||||
void SetMapMsg(const stpb::MapMsg& st, pb::MapMsg& msg) {
|
||||
msg.Clear();
|
||||
for (const auto& pair : st.sfix64_str_map) {
|
||||
(*msg.mutable_sfix64_str_map())[pair.first.val] = pair.second;
|
||||
}
|
||||
for (const auto& pair : st.str_iguana_type_msg_map) {
|
||||
pb::IguanaTypeMsg* it_msg =
|
||||
&((*msg.mutable_str_iguana_type_msg_map())[pair.first]);
|
||||
SetIguanaTypeMsg(pair.second, *it_msg);
|
||||
}
|
||||
for (const auto& pair : st.int_repeat_base_msg_map) {
|
||||
pb::RepeatBaseTypeMsg* rb_msg =
|
||||
&((*msg.mutable_int_repeat_base_msg_map())[pair.first]);
|
||||
SetRepeatBaseTypeMsg(pair.second, *rb_msg);
|
||||
}
|
||||
}
|
||||
|
||||
void CheckMapMsg(const stpb::MapMsg& st, const pb::MapMsg& msg) {
|
||||
CHECK(msg.sfix64_str_map_size() == st.sfix64_str_map.size());
|
||||
for (const auto& pair : st.sfix64_str_map) {
|
||||
auto it = msg.sfix64_str_map().find(pair.first.val);
|
||||
CHECK(it != msg.sfix64_str_map().end());
|
||||
CHECK(it->second == pair.second);
|
||||
}
|
||||
CHECK(msg.str_iguana_type_msg_map_size() ==
|
||||
st.str_iguana_type_msg_map.size());
|
||||
for (const auto& pair : st.str_iguana_type_msg_map) {
|
||||
auto it = msg.str_iguana_type_msg_map().find(pair.first);
|
||||
CHECK(it != msg.str_iguana_type_msg_map().end());
|
||||
CheckIguanaTypeMsg(pair.second, it->second);
|
||||
}
|
||||
|
||||
CHECK(msg.int_repeat_base_msg_map_size() ==
|
||||
st.int_repeat_base_msg_map.size());
|
||||
for (const auto& pair : st.int_repeat_base_msg_map) {
|
||||
auto it = msg.int_repeat_base_msg_map().find(pair.first);
|
||||
CHECK(it != msg.int_repeat_base_msg_map().end());
|
||||
CheckRepeatBaseTypeMsg(pair.second, it->second);
|
||||
}
|
||||
}
|
||||
|
||||
void SetBaseOneofMsg(const stpb::BaseOneofMsg& st, pb::BaseOneofMsg& msg) {
|
||||
msg.set_optional_int32(st.optional_int32);
|
||||
msg.set_optional_double(st.optional_double);
|
||||
|
||||
std::visit(
|
||||
[&](auto& value) {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<T, double>) {
|
||||
msg.set_one_of_double(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string>) {
|
||||
msg.set_one_of_string(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, stpb::BaseTypeMsg>) {
|
||||
auto* submsg = msg.mutable_one_of_base_type_msg();
|
||||
SetBaseTypeMsg(value, *submsg);
|
||||
}
|
||||
},
|
||||
st.one_of);
|
||||
}
|
||||
|
||||
void CheckBaseOneofMsg(const stpb::BaseOneofMsg& st,
|
||||
const pb::BaseOneofMsg& msg) {
|
||||
CHECK(st.optional_int32 == msg.optional_int32());
|
||||
CHECK(st.optional_double == msg.optional_double());
|
||||
|
||||
std::visit(
|
||||
[&](auto& value) {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<T, double>) {
|
||||
CHECK(value == msg.one_of_double());
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, std::string>) {
|
||||
CHECK(value == msg.one_of_string());
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, stpb::BaseTypeMsg>) {
|
||||
CheckBaseTypeMsg(value, msg.one_of_base_type_msg());
|
||||
}
|
||||
},
|
||||
st.one_of);
|
||||
}
|
||||
|
||||
void SetNestOneofMsg(const stpb::NestOneofMsg& st, pb::NestOneofMsg& msg) {
|
||||
std::visit(
|
||||
[&](auto& value) {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<T, std::string>) {
|
||||
msg.set_base_one_of_string(value);
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, stpb::BaseOneofMsg>) {
|
||||
auto* submsg = msg.mutable_base_one_of_msg();
|
||||
SetBaseOneofMsg(value, *submsg);
|
||||
}
|
||||
},
|
||||
st.nest_one_of_msg);
|
||||
}
|
||||
|
||||
void CheckNestOneofMsg(const stpb::NestOneofMsg& st,
|
||||
const pb::NestOneofMsg& msg) {
|
||||
std::visit(
|
||||
[&](auto& value) {
|
||||
using T = std::decay_t<decltype(value)>;
|
||||
if constexpr (std::is_same_v<T, std::string>) {
|
||||
CHECK(value == msg.base_one_of_string());
|
||||
}
|
||||
else if constexpr (std::is_same_v<T, stpb::BaseOneofMsg>) {
|
||||
CheckBaseOneofMsg(value, msg.base_one_of_msg());
|
||||
}
|
||||
},
|
||||
st.nest_one_of_msg);
|
||||
}
|
||||
#endif
|
||||
|
||||
inline void print_hex_str(const std::string& str) {
|
||||
std::ostringstream oss;
|
||||
oss << std::hex << std::setfill('0');
|
||||
for (unsigned char c : str) {
|
||||
oss << std::setw(2) << static_cast<int>(c);
|
||||
}
|
||||
std::cout << oss.str() << std::endl;
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
syntax = "proto3";
|
||||
|
||||
package pb;
|
||||
|
||||
option optimize_for = SPEED;
|
||||
|
||||
enum Enum {
|
||||
ZERO = 0;
|
||||
FOO = 1;
|
||||
BAR = 2;
|
||||
BAZ = 123456;
|
||||
NEG = -1; // Intentionally negative.
|
||||
}
|
||||
|
||||
message BaseTypeMsg {
|
||||
int32 optional_int32 = 1;
|
||||
int64 optional_int64 = 2;
|
||||
uint32 optional_uint32 = 3;
|
||||
uint64 optional_uint64 = 4;
|
||||
float optional_float = 5;
|
||||
double optional_double = 6;
|
||||
bool optional_bool = 7;
|
||||
string optional_string = 8;
|
||||
Enum optional_enum = 9;
|
||||
}
|
||||
|
||||
message RepeatBaseTypeMsg {
|
||||
repeated uint32 repeated_uint32 = 1;
|
||||
repeated uint64 repeated_uint64 = 2;
|
||||
repeated int32 repeated_int32 = 3;
|
||||
repeated int64 repeated_int64 = 4;
|
||||
repeated float repeated_float = 5;
|
||||
repeated double repeated_double = 6;
|
||||
repeated string repeated_string = 7;
|
||||
repeated Enum repeated_enum = 8;
|
||||
}
|
||||
|
||||
message IguanaTypeMsg {
|
||||
sint32 optional_sint32 = 1;
|
||||
sint64 optional_sint64 = 2;
|
||||
fixed32 optional_fixed32 = 3;
|
||||
fixed64 optional_fixed64 = 4;
|
||||
sfixed32 optional_sfixed32 = 5;
|
||||
sfixed64 optional_sfixed64 = 6;
|
||||
}
|
||||
|
||||
message RepeatIguanaTypeMsg {
|
||||
repeated sfixed32 repeated_sint32 = 1;
|
||||
repeated sfixed64 repeated_sint64 = 2;
|
||||
repeated fixed32 repeated_fixed32 = 3;
|
||||
repeated fixed64 repeated_fixed64 = 4;
|
||||
repeated sfixed32 repeated_sfixed32 = 5;
|
||||
repeated sfixed64 repeated_sfixed64 = 6;
|
||||
}
|
||||
|
||||
message NestedMsg {
|
||||
BaseTypeMsg base_msg = 1;
|
||||
repeated BaseTypeMsg repeat_base_msg = 2;
|
||||
IguanaTypeMsg iguana_type_msg = 3;
|
||||
repeated IguanaTypeMsg repeat_iguna_msg = 4;
|
||||
repeated RepeatBaseTypeMsg repeat_repeat_base_msg = 5;
|
||||
}
|
||||
|
||||
message MapMsg {
|
||||
map<sfixed64, string> sfix64_str_map = 1;
|
||||
map<string, IguanaTypeMsg> str_iguana_type_msg_map = 2;
|
||||
map<int32, RepeatBaseTypeMsg> int_repeat_base_msg_map = 3;
|
||||
// Key in map fields cannot be float/double, bytes or message types.
|
||||
}
|
||||
|
||||
message BaseOneofMsg {
|
||||
int32 optional_int32 = 1;
|
||||
oneof one_of {
|
||||
double one_of_double = 2;
|
||||
string one_of_string = 3;
|
||||
BaseTypeMsg one_of_base_type_msg = 4;
|
||||
}
|
||||
double optional_double = 5;
|
||||
}
|
||||
|
||||
message NestOneofMsg {
|
||||
oneof nest_one_of_msg {
|
||||
string base_one_of_string = 1;
|
||||
BaseOneofMsg base_one_of_msg = 2;
|
||||
}
|
||||
}
|
||||
|
||||
message Simple {
|
||||
int32 a = 1;
|
||||
int32 b = 2;
|
||||
int64 c = 3;
|
||||
int64 d = 4;
|
||||
string str = 5;
|
||||
}
|
||||
|
||||
enum Color {
|
||||
Red = 0;
|
||||
Green = 1;
|
||||
Blue = 2;
|
||||
}
|
||||
|
||||
message Simple2 {
|
||||
int32 a = 1;
|
||||
int32 b = 2;
|
||||
Color c = 3;
|
||||
int64 d = 4;
|
||||
string str = 5;
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue